一、下载源码
下载地址:https://github.com/vvipi/py3_demo_on_vnpy_ctp,下载后并解压缩。
二、修改配置文件
(1)修改setting文件夹下面的user.json文件
"userID": "", "password": "a4", "brokerID": "9999", "MdIp": "tcp://180.168.146.187:10011", "TdIp": "tcp://180.168.146.187:10001"
(2)修改modules文件夹下面的baseSetting.py文件,将下面这行代码修改为你的py3_ctp_demo_on_vnpy所在目录。
WORKING_DIR = 'C:/Users/Kevin/py3_ctp_demo_on_vnpy/'
三、启动项目
直接执行python demoMain.py即可。
四、项目分析
除了demoMain.py,还有6个文件夹,
log: \log\EventLog\下面存储日志。
modules: 存储的是自己开发的模块,包括eventEngine、eventType、ctpApi、ctaEngine等。
resource: 里面只有fs.ico这一个文件(程序的ICO)
setting: 有user.json、CTA_setting.json两个json文件。
strategy: 放置策略的文件夹
temp: 保存的合约对象
五、源码分析
首先从demoMain.py开始。
# 系统模块 from datetime import datetime, time, timedelta import json import shelve import functools # 自己开发的模块 from modules.ctpApi import * from modules.eventEngine import * from modules.eventType import * from modules.ctaEngine import CtaEngine from modules.rmEngine import * from modules.uiWidgets import * from modules.objects import * from modules.baseSetting import WORKING_DIR, USER_FILE, globalSetting
(1)timedelta
该函数表示两个时间的间隔,其实我之前已经用过了。
import datetime today=datetime.date.today() oneday=datetime.timedelta(days=1) yesterday =(today-oneday).strftime("%Y%m%d") print(yesterday)
用另一种方法
from datetime import datetime,timedelta now = datetime.now(); yesterday = now - timedelta(days = 1); print(yesterday.strftime("%Y%m%d"))
(2)shelve
shelve是一额简单的数据存储方案,他只有一个函数就是open(),这个函数接收一个参数就是文件名,并且文件名必须是.bat类型的。
shelve也是一个用来持久化Python对象的简单工具。当我们写程序的时候如果不想用关系数据库那么重量级的东东去存储数据,不妨可以试试用shelve。shelf也是用key来访问的,使用起来和字典类似。注意的是,在shelve模块中,key必须为字符串,而值可以是python所支持的数据类型。另外,shelve其实用anydbm去创建DB并且管理持久化对象的。
程序中相关的代码:
def saveContracts(self): """保存所有合约对象到硬盘""" contractFilePath = WORKING_DIR + 'temp/contracts' f = shelve.open(contractFilePath) f['data'] = self.contractDict f.close() #---------------------------------------------------------------------- def loadContracts(self): """从硬盘读取合约对象""" contractFilePath = WORKING_DIR + 'temp/contracts' f = shelve.open(contractFilePath) if 'data' in f: d = f['data'] for key, value in d.items(): self.contractDict[key] = value f.close()
(3)functools
functools,用于高阶函数:指那些作用于函数或者返回其它函数的函数,通常只要是可以被当做函数调用的对象就是这个模块的目标。
在Python 2.7 中具备如下方法,
cmp_to_key,将一个比较函数转换关键字函数;
partial,针对函数起作用,并且是部分的;
reduce,与python内置的reduce函数功能一样;
total_ordering,在类装饰器中按照缺失顺序,填充方法;
update_wrapper,更新一个包裹(wrapper)函数,使其看起来更像被包裹(wrapped)的函数;
wraps,可用作一个装饰器,简化调用update_wrapper的过程;functool.wraps就是调用函数装饰器partial(update_wrapper, wrapped=wrapped, assigned=assigned, updated=updated)的简写
在文件中的用法如下:
def stand_alone(func): ''' 装饰器 如果已经有实例在跑则退出 ''' @functools.wraps(func) def f(*args,**kwargs): import socket try: # 全局属性,否则变量会在方法退出后被销毁 global soket_bind soket_bind = socket.socket() host = socket.gethostname() soket_bind.bind((host, 9527)) except: print('已经运行一个实例,不能重复打开') return return func(*args,**kwargs) return f
装饰器的作用是接受一个被包裹函数作为参数,对其进行加工,返回一个包裹函数。
可参考文档:https://www.cnblogs.com/Security-Darren/p/4168310.html#t7
https://blog.csdn.net/hang916/article/details/79528275
六、尾部源码
if __name__ == '__main__': # 显示自定义图标 import ctypes ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID("myappid") import sys app = QApplication(sys.argv) try: import qdarkstyle app.setStyleSheet(qdarkstyle.load_stylesheet_pyqt5()) # 黑色主题 app.setFont(QFont("Microsoft YaHei", 11)) # 微软雅黑字体 except: pass main = MainEngine() main.login() app.exec_()
(1)ctypes模块
python提供的一个外部函数库 ctypes, 它提供了C语言兼容的几种数据类型,并且可以允许调用C编译好的库。
这两行代码的意思是设置Windows底部任务栏图标。
在网上看到如下的代码:
#设置窗口图标,下面两句实现任务栏图标与窗口图标一致 import ctypes ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(“Calculator”) self.ui.setupUi(self)
(2)QApplication
QApplication应该是PyQt5里的,因为见过如下的代码:
from PyQt5.QtWidgets import QApplication, QWidget
app = QApplication(sys.argv)的意思是:所有的PyQt5应用必须创建一个应用(Application)对象。sys.argv参数是一个来自命令行的参数列表。Python脚本可以在shell中运行。这是我们用来控制我们应用启动的一种方法。
(3)qdarkstyle
qdarkstyle的用法可以见官方介绍。
上面的那一行代码其实是以下两行代码的合并写法:
# PyQt5 dark_stylesheet = qdarkstyle.load_stylesheet_pyqt5() app.setStyleSheet(dark_stylesheet)
(4)MainEngine
main = MainEngine()这里实例化一个类。
(5)app.exec_()
exec_()方法有一个下划线。因为exec是Python保留关键字。因此,用exec_()来代替。
关于PyQt5的一些用法,可以看这个简单的教程:https://www.cnblogs.com/archisama/p/5444032.html
比如,下面的代码就是显示一个简单的窗口:
import sys from PyQt5.QtWidgets import QApplication, QWidget if __name__ == '__main__': app = QApplication(sys.argv) w = QWidget() w.resize(250, 150) #控制窗口大小 w.move(300, 300) #控制窗口在屏幕上的显示位置 w.setWindowTitle('Simple') w.show() sys.exit(app.exec_())
最后一句不加sys.exit()也可以运行,但看网上教程都是加的,使用sys.exit()方法确保程序能够完美的退出。
运行效果如下: