蜗牛博客VNPY源码学习系列文章
VNPY源码(一)CTP封装及K线合成
VNPY源码(二)API获取行情和script_trader
VNPY源码(三)主引擎MainEngine
VNPY源码(四)DataRecorder
VNPY源码(五)CtaEngine实盘引擎
VNPY源码(六)BacktesterEngine回测引擎
VNPY源码(七)限价单与停止单
VNPY源码(八)VNPY的数据流
一、接收行情、并由Tick生成1分钟K线的Demo
# -*- coding: utf-8 -*-
import thostmduserapi as mdapi
class CFtdcMdSpi(mdapi.CThostFtdcMdSpi):
tapi=''
def __init__(self,tapi):
mdapi.CThostFtdcMdSpi.__init__(self)
self.tapi=tapi
def OnFrontConnected(self) -> "void":
#这个是在执行了join函数后执行的。
#它是底层dll文件调用的
#当客户端与交易托管系统建立起通信连接时(还未登录前),该方法被调用。本方法在完成初始化后调用,可以在其中完成用户登录任务。
print("1.当客户端与交易托管系统建立起通信连接时(还未登录前),OnFrontConnected方法被调用")
print ("OnFrontConnected")
loginfield = mdapi.CThostFtdcReqUserLoginField()
loginfield.BrokerID="9999"
loginfield.UserID="1xxxx1"
loginfield.Password="axxxx4"
loginfield.UserProductInfo="python dll"
self.tapi.ReqUserLogin(loginfield,0)
def OnRspUserLogin(self, pRspUserLogin: 'CThostFtdcRspUserLoginField', pRspInfo: 'CThostFtdcRspInfoField', nRequestID: 'int', bIsLast: 'bool') -> "void":
#登录请求响应,当ReqUserLogin后,该方法被调用。
print ("2.登录请求响应,当ReqUserLogin后,OnRspUserLogin方法被调用")
print ("OnRspUserLogin")
print ("SessionID=",pRspUserLogin.SessionID)
print ("ErrorID=",pRspInfo.ErrorID)
print ("ErrorMsg=",pRspInfo.ErrorMsg)
# ret=self.tapi.SubscribeMarketData([b"ru1910",b"rb1909",b"au1911",b"ag1912"],4)
ret=self.tapi.SubscribeMarketData([b"ag1912"],1)
def OnRtnDepthMarketData(self, pDepthMarketData: 'CThostFtdcDepthMarketDataField') -> "void":
#深度行情通知,当SubscribeMarketData订阅行情后,行情通知由此推送。
print("3.深度行情通知,当SubscribeMarketData订阅行情后,行情通知由此推送")
# print ("OnRtnDepthMarketData")
# print ("InstrumentID=",pDepthMarketData.InstrumentID)
# print ("LastPrice=",pDepthMarketData.LastPrice)
print("当前代码为{},价格为{}".format(pDepthMarketData.InstrumentID,pDepthMarketData.LastPrice))
print ("当前时间=",pDepthMarketData.UpdateTime)
self.chuli(pDepthMarketData)
print(pDepthMarketData)
def OnRspSubMarketData(self, pSpecificInstrument: 'CThostFtdcSpecificInstrumentField', pRspInfo: 'CThostFtdcRspInfoField', nRequestID: 'int', bIsLast: 'bool') -> "void":
#订阅行情应答,调用SubscribeMarketData后,通过此接口返回
print("4.订阅行情应答,调用SubscribeMarketData后,通过此接口返回")
print ("OnRspSubMarketData")
print ("InstrumentID=",pSpecificInstrument.InstrumentID)
print ("ErrorID=",pRspInfo.ErrorID)
print ("ErrorMsg=",pRspInfo.ErrorMsg)
def chuli(self,tickshuju,huancun=[]):
zongfen=tickshuju.UpdateTime[:-2]+"00"
if huancun==[]:
huancun.append(tickshuju.TradingDay)
huancun.append(zongfen)
huancun.append(float(tickshuju.LastPrice))
print(huancun)
print(huancun[1])
print(zongfen)
print(zongfen!=huancun[1])
else:
if zongfen!=huancun[1]:#xieshuju(huancun)
print("hi"*100)
print(huancun)
xieshuju(huancun)
huancun[0]=tickshuju.TradingDay
huancun[1]=tickshuju.UpdateTime
huancun[2]=float(tickshuju.LastPrice)
else:
a=tickshuju.LastPrice
c=max(a,huancun[2])
huancun[2]=c
print("over"*100)
def xieshuju(shujuliebiao):
f2=open("haha.txt","a")
f2.write(str(shujuliebiao))
f2.close()
def main():
#调用thostmduserapi文件中的CThostFtdcMdApi_CreateFtdcMdApi函数,它输出的是CThostFtdcMdApi实例
mduserapi=mdapi.CThostFtdcMdApi_CreateFtdcMdApi()
print("1"*50)
#实例化一个CFtdcMdSpi类,将上面的CThostFtdcMdApi作为参数传入。
#执行CFtdcMdSpi的init方法,其实是调用父类CThostFtdcMdSpi的方法。
#父类CThostFtdcMdSpi的init的方法,如果self.__class__ == CThostFtdcMdSpi,_self = None,否则_self = self
# 将上面的_self传入到_thostmduserapi.new_CThostFtdcMdSpi(_self, ) ,执行从c编译文件中引入的_thostmduserapi里面的CThostFtdcMdSpi_swiginit()功能
# 将_thostmduserapi.delete_CThostFtdcMdSpi赋值给__swig_destroy__。
mduserspi=CFtdcMdSpi(mduserapi)
print("2"*50)
#注意是第一步输出的mduserapi,执行CThostFtdcMdApi类的RegisterFront函数,这个函数返回的是“void"?
# mduserapi.RegisterFront("tcp://101.230.209.178:53313")
print("3"*50)
'''以下是7*24小时环境'''
mduserapi.RegisterFront("tcp://180.168.146.187:10131")
#传入的参数是 CThostFtdcTraderSpi
mduserapi.RegisterSpi(mduserspi)
print("4"*50)
#执行CThostFtdcMdApi的Init函数(不是init),返回一个void
mduserapi.Init()
print("5"*50)
#执行CThostFtdcMdApi的join函数,返回一个int。
mduserapi.Join()
print("6"*50)
x =OnRtnDepthMarketData()
dwbtest(x)
if __name__ == '__main__':
main()
效果展示:

二、Emu
今天想使用vnpy的BarGenerator的时候,发现相关代码有一句from enum import Enum。
枚举类型可以看作是一种标签或是一系列常量的集合,通常用于表示某些特定的有限集合,例如星期、月份、状态等。
使用普通类可直接实现枚举:
class color():
YELLOW = 1
RED = 2
GREEN = 3
PINK = 4
# 访问枚举项
print(color.YELLOW) # 1
虽然这样是可以解决问题的,但是并不严谨,也不怎么安全,比如:
1、枚举类中,不应该存在key相同的枚举项(类变量)
2、不允许在类外直接修改枚举项的值
使用枚举
# 导入枚举类
from enum import Enum
# 继承枚举类
class color(Enum):
YELLOW = 1
BEOWN = 1
# 注意BROWN的值和YELLOW的值相同,这是允许的,此时的BROWN相当于YELLOW的别名
RED = 2
GREEN = 3
PINK = 4
可参考:https://www.cnblogs.com/-beyond/p/9777329.html
三、dataclasses
Python 3.7 的新特性。
Dataclasses 是 Python 的类(LCTT 译注:更准确的说,它是一个模块),适用于存储数据对象。
那么它有什么特点呢?它们可以与同一类型的其他对象进行比较。例如:一个数字可以是 greater than(大于)、less than(小于) 或 equal(等于) 另一个数字。这样是不是很方便?
如果你想要将类转换为dataclasses,只需要使用dataclass作装饰器即可。
@dataclass
class BaseData:
"""
Any data object needs a gateway_name as source
and should inherit base data.
"""
gateway_name: str
四、Callable
有一条from typing import Callable。
动态语言写起来非常爽,便是后期的维护是一个坑,python3.5之后,PEP484为python引入了类型注解,让Python能够像静态语言一样支持类型声明。比如:
#一个典型的函数注释例子,为参数加上了类型
def greeting(name: str) -> str:
return 'Hello ' + name
python3.6之后,引入了对变量类型的声明
# 声明primes是列表,其元素的类型为int。并给primes赋值一个空列表。
primes: List[int] = []
# 声明captain的类型是str,注意这里无初始值
captain: str
# 声明stats是类变量,类型是字典(key的类型为str、value的类型为int)。并给stats赋值一个空字典。
class Starship:
stats: ClassVar[Dict[str, int]] = {}
目前在Python标准库中,有一个暂不稳定的库:typing。typing提供了最基本的声明类型,用户可以像引入普通库一样将其中的类型引入文档中使用,同时提供了NewType()函数让用户能够很方便地创建自定义类型。此模块的完整规范记录在PEP484中。
回调函数可以使用类似Callable[[Arg1Type, Arg2Type],ReturnType]的类型注释:
from typing import Callable
def feeder(get_next_item: Callable[[], str]) -> None:
# Body
def async_query(on_success: Callable[[int], None],
on_error: Callable[[int, Exception], None]) -> None:
# Body
可参考:https://www.cnblogs.com/lynsyklate/p/7594082.html
五、python新特性:
https://www.cnblogs.com/animalize/p/5633215.html
参考资料:
python ctp API: https://github.com/nicai0609/Python-CTPAPI
我也想只用vnpy的接口,不用他的回测框架。请问你用的vnpy哪个版本做的这个,我用2.0版本没有你写的这些模块啊。