├── .gitignore ├── LICENSE ├── MultipleAccountUpdater ├── MultipleAccountUpdater.py ├── config.json ├── log │ └── deleteme ├── py_ctp │ ├── __init__.py │ ├── ctp_api.py │ ├── ctp_data_type.py │ ├── eventEngine.py │ ├── thosttraderapi.dll │ └── vnctptd.pyd └── tradeDate.json └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows: 2 | Thumbs.db 3 | ehthumbs.db 4 | Desktop.ini 5 | 6 | # Python: 7 | *.py[cod] 8 | *.so 9 | *.egg 10 | *.egg-info 11 | dist 12 | build 13 | 14 | # My configurations: -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Zhang Li 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /MultipleAccountUpdater/MultipleAccountUpdater.py: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | ''' 3 | 读取账户资金、持仓、委托信息,保存至本地 4 | 加入守护者进程,自动开关 5 | 支持多账户 6 | ''' 7 | import multiprocessing 8 | from PyQt5.QtWidgets import QApplication 9 | from datetime import datetime, time 10 | import json 11 | import os 12 | import logging 13 | from py_ctp.ctp_api import * 14 | from py_ctp.eventEngine import * 15 | import functools 16 | 17 | # 配置日志 18 | path = 'log/Log{date}'.format(date=datetime.now().strftime('%Y-%m-%d')) 19 | logging.basicConfig(filename=path, level=logging.INFO) 20 | 21 | 22 | ONEDRIVE_DIR = 'C:/OneDrive/' # 存放生成的记录的目录 23 | # ONEDRIVE_DIR = 'X:/db_werobot/' 24 | # 设置文件 25 | CONFIG_FILE = 'config.json' 26 | # 时间 27 | NIGHT_START = time(20, 47) # 夜盘开盘 28 | # NIGHT_END = time(23, 59, 59) 29 | # MORNING_START = time(0, 0) # 夜盘跨过0点,分两段 30 | MORNING_END = time(2, 31) 31 | DAY_START = time(8, 47) # 日盘开盘 32 | DAY_END = time(15, 35) # 日盘收盘 33 | 34 | def stand_alone(func): 35 | ''' 36 | 装饰器 37 | 如果已经有实例在跑则退出 38 | :return: 39 | ''' 40 | @functools.wraps(func) 41 | def f(*args,**kwargs): 42 | import socket 43 | try: 44 | # 全局属性,否则变量会在方法退出后被销毁 45 | global soket_bind 46 | soket_bind = socket.socket() 47 | host = socket.gethostname() 48 | soket_bind.bind((host, 7788)) 49 | except: 50 | print('已经运行一个实例,不能重复打开') 51 | return None 52 | return func(*args,**kwargs) 53 | return f 54 | 55 | @stand_alone 56 | class MainEngine: 57 | """主引擎,负责对API的调度""" 58 | #---------------------------------------------------------------------- 59 | def __init__(self, config): 60 | """Constructor""" 61 | self.ee = EventEngine() # 创建事件驱动引擎 62 | self.ee.start() # 启动事件驱动引擎 63 | self.userID = '' # 账号 64 | self.password = '' # 密码 65 | self.brokerID = '' # 经纪商代码 66 | self.TdIp = '' # 交易服务器地址 67 | 68 | self.set_up(config) # 设置账号 69 | 70 | # 循环查询持仓和账户相关 71 | self.todayBalance = [] 72 | self.countGet = 0 # 查询延时计数 73 | self.lastGet = 'Position' # 上次查询的性质,先查询账户 74 | # 统计净值 75 | self.navCalculated = False 76 | self.navComfirmed = False 77 | 78 | #持仓和账户、委托 79 | self.ee.register((EVENT_START + self.userID), self.startReq) # 开始查询 80 | self.ee.register((EVENT_ACCOUNT + self.userID), self.account) 81 | self.ee.register(EVENT_POSITION + self.userID, self.position) 82 | self.ee.register((EVENT_ORDER + self.userID), self.updateOrder) 83 | self.ee.register(EVENT_LOG, self.print_log) 84 | self.td = CtpTdApi(self, self.ee) # 创建交易API接口 85 | #持仓、账户、委托、净值数据 86 | self.dict_account ={} 87 | self.dict_position ={} 88 | self.orderDict ={} 89 | self.workingOrderDict = {} 90 | self.nav = {} 91 | 92 | self.clear_history() # 开启软件时清空一次委托记录 93 | 94 | def __del__(self): 95 | self.ee.unregister(EVENT_TIMER, self.getAccountPosition) 96 | self.ee.unregister(EVENT_ACCOUNT + self.userID, self.account) 97 | self.ee.unregister(EVENT_POSITION + self.userID, self.position) 98 | self.ee.unregister(EVENT_ORDER + self.userID, self.updateOrder) 99 | self.ee.stop() # 停止事件驱动引擎 100 | #---------------------------------------------------------------------- 101 | def login(self): 102 | """登陆""" 103 | self.td.connect(self.userID, self.password, self.brokerID, self.TdIp) 104 | self.put_log('用户%s已登录' % self.userID) 105 | # 登录时清空委托列表 106 | self.orderDict = {} 107 | #---------------------------------------------------------------------- 108 | def print_log(self, event): 109 | log = event.dict_['log'] 110 | print(log) 111 | t = datetime.now().strftime('%Y-%m-%d %H:%M:%S ') 112 | log = ''.join([t, log]) 113 | logging.info(log) 114 | #---------------------------------------------------------------------- 115 | def put_log(self, log): 116 | event = Event() 117 | event.dict_['log'] = log 118 | event.type_ = EVENT_LOG 119 | self.ee.put(event) 120 | #---------------------------------------------------------------------- 121 | def set_up(self, config): 122 | '''set up args''' 123 | self.userID = config['userID'] # 账号 124 | self.password = config['password'] # 密码 125 | self.brokerID = config['brokerID'] # 经纪商代码 126 | self.TdIp = config['TdIp'] # 交易服务器地址 127 | 128 | # 当天重启软件时载入之前的资金记录,顺便加在这里 /摊手 129 | try: 130 | path = os.path.join(ONEDRIVE_DIR, self.userID + '/balance.json') 131 | with open(path, 'r', encoding="utf-8") as f: 132 | historyBalance = json.load(f) 133 | except FileNotFoundError: 134 | return 135 | if len(historyBalance) > 0: 136 | lastUpdatetime = historyBalance[0]['updateTime'] 137 | lastUpdatetime = datetime.strptime(lastUpdatetime, '%Y-%m-%d_%H:%M:%S') 138 | t = datetime.now() 139 | if t - lastUpdatetime < timedelta(hours=6): # 如果当天出错或重启,不清空盘中资金的数据 140 | self.todayBalance = historyBalance 141 | #---------------------------------------------------------------------- 142 | def startReq(self, event): 143 | self.ee.register(EVENT_TIMER, self.getAccountPosition) # 定时器事件,循环查询 144 | self.ee.unregister(EVENT_START + self.userID, self.startReq) 145 | self.put_log(''.join([self.userID, '开始查询'])) 146 | #---------------------------------------------------------------------- 147 | def clear_history(self): 148 | self.save_nontrade() 149 | self.save_order() 150 | 151 | def save_balance(self): 152 | path = os.path.join(ONEDRIVE_DIR, self.userID + '/balance.json') 153 | with open(path, 'w', encoding="utf-8") as f: 154 | jsonD = json.dumps(self.todayBalance, indent=4) 155 | f.write(jsonD) 156 | def save_order(self): 157 | path = os.path.join(ONEDRIVE_DIR, self.userID + '/order.json') 158 | with open(path, 'w', encoding="utf-8") as f: 159 | data = json.dumps(self.orderDict, indent=4) 160 | f.write(data) 161 | def save_nontrade(self): 162 | path = os.path.join(ONEDRIVE_DIR, self.userID + '/nontrade.json') 163 | with open(path, 'w', encoding="utf-8") as f: 164 | data = json.dumps(self.workingOrderDict, indent=4) 165 | f.write(data) 166 | def save_nav(self): 167 | path = os.path.join(ONEDRIVE_DIR, self.userID + '/nav.json') 168 | with open(path, 'w', encoding="utf-8") as f: 169 | data = json.dumps(self.nav, indent=4) 170 | f.write(data) 171 | #---------------------------------------------------------------------- 172 | def getAccountPosition(self, event): 173 | """循环查询账户和持仓""" 174 | self.countGet += 1 175 | # 每n秒发一次查询 176 | if self.countGet > 8: 177 | self.countGet = 0 # 清空计数 178 | 179 | if self.lastGet == 'Account': 180 | self.getPosition() 181 | self.lastGet = 'Position' 182 | else: 183 | self.getAccount() 184 | self.lastGet = 'Account' 185 | # ---------------------------------------------------------------------- 186 | def account(self, event):# 处理账户事件数据 187 | var = event.dict_['data'] 188 | balance = int(var["Balance"]) 189 | dw = int(var["Deposit"] - var["Withdraw"]) 190 | # 保存权益,供收盘时自动发送净值 191 | t = datetime.now().time() 192 | # 只记录有交易的时间段 193 | trading = time(20, 59) < t < time(23, 59, 59) or time(0, 0) < t < time(1, 31) or time(8, 59) < t < time(11, 31) or time(13, 29)< t < time(15, 1) 194 | if trading: 195 | updateTime = datetime.now().strftime('%Y-%m-%d_%H:%M:%S') 196 | data = { 197 | 'balance': balance, 198 | 'updateTime': updateTime, 199 | 'DepositWithdraw': dw, 200 | } 201 | self.todayBalance.append(data) 202 | self.save_balance() 203 | 204 | onClose = time(15, 1) < t < time(15, 2) 205 | onComfirm = time(15, 31) < t < time(15, 32) 206 | if onComfirm: 207 | # 停止出入金后确认出入金情况 208 | self.todayBalance[-1]['DepositWithdraw'] = dw 209 | self.save_balance() 210 | 211 | if onClose and not self.navCalculated: 212 | # 净值统计任务 213 | self.calculate_nav() 214 | self.navCalculated = True 215 | 216 | if onComfirm and not self.navComfirmed: 217 | # 净值确认任务 218 | self.calculate_nav() 219 | self.navComfirmed = True 220 | # ---------------------------------------------------------------------- 221 | def position(self, event):#处理持仓事件数据 222 | pos = event.dict_['data'] 223 | last = event.dict_['last'] 224 | dm = { 225 | DIRECTION_LONG:"多持", 226 | DIRECTION_SHORT:"空持", 227 | } 228 | 229 | if pos.position is not 0: 230 | posName = '.'.join([pos.symbol + pos.direction]) 231 | if posName not in self.dict_position.keys(): 232 | tmp = {} 233 | tmp["合约名称"] = pos.name 234 | tmp["持仓方向"] = dm.get(pos.direction, '未知方向') 235 | tmp["总持仓量"] = pos.position 236 | tmp["昨持仓量"] = pos.ydPosition 237 | tmp["今持仓量"] = pos.position - pos.ydPosition 238 | tmp["开仓盈亏"] = pos.openProfit 239 | self.dict_position[posName] = tmp 240 | 241 | # 保存持仓数据到文件 242 | if last: 243 | path = ''.join([ONEDRIVE_DIR, self.userID, '/position.json']) 244 | with open(path, 'w', encoding="utf-8") as f: 245 | jsonD = json.dumps(self.dict_position, indent=4) 246 | f.write(jsonD) 247 | 248 | self.dict_position.clear() # 清空 249 | 250 | # ---------------------------------------------------------------------- 251 | def updateOrder(self, event): 252 | """""" 253 | var = event.dict_['data'] 254 | index = str(var["OrderLocalID"])+'.'+var["InstrumentID"] 255 | # 更新委托单 256 | if index not in self.orderDict.keys(): 257 | self.orderDict[index] = {} 258 | self.orderDict[index]["合约代码"] = (str(var["InstrumentID"])) 259 | self.orderDict[index]["时间"] = str(var["InsertTime"]) 260 | self.orderDict[index]["价格"] = (str(var["LimitPrice"])) 261 | self.orderDict[index]["数量"] = (str(var["VolumeTotalOriginal"])) 262 | self.orderDict[index]["状态信息"] = (str(var["OrderStatus"])) 263 | if var["CombOffsetFlag"] == OFFSET_OPEN: 264 | if var["Direction"] == DIRECTION_LONG: 265 | self.orderDict[index]["买卖开平标志"] = ('多开') 266 | else: 267 | self.orderDict[index]["买卖开平标志"] = ('空开') 268 | else: 269 | if var["Direction"] == DIRECTION_SHORT: 270 | self.orderDict[index]["买卖开平标志"] = ('多平') 271 | else: 272 | self.orderDict[index]["买卖开平标志"] = ('空平') 273 | # 更新可能变化的数据 274 | else: 275 | self.orderDict[index]["状态信息"] = str(var["OrderStatus"]) 276 | # 保存到本地 277 | self.save_order() 278 | 279 | # 更新可撤单 280 | if index not in self.workingOrderDict.keys() and var["StatusMsg"] == '未成交': 281 | self.workingOrderDict[index] = {} 282 | # 准备保存到本地的未成交信息 283 | self.workingOrderDict[index]["时间"] = str(var["InsertTime"]) 284 | self.workingOrderDict[index]["合约代码"] = (str(var["InstrumentID"])) 285 | self.workingOrderDict[index]["价格"] = (str(var["LimitPrice"])) 286 | self.workingOrderDict[index]["数量"] = (str(var["VolumeTotalOriginal"])) 287 | self.workingOrderDict[index]["状态信息"] = (str(var["StatusMsg"])) 288 | if var["CombOffsetFlag"] == OFFSET_OPEN: 289 | if var["Direction"] == DIRECTION_LONG: 290 | self.workingOrderDict[index]["买卖开平标志"] = ('多开') 291 | else: 292 | self.workingOrderDict[index]["买卖开平标志"] = ('空开') 293 | else: 294 | if var["Direction"] == DIRECTION_SHORT: 295 | self.workingOrderDict[index]["买卖开平标志"] = ('多平') 296 | else: 297 | self.workingOrderDict[index]["买卖开平标志"] = ('空平') 298 | # 更新状态 299 | if index in self.workingOrderDict.keys(): 300 | self.workingOrderDict[index]["状态信息"] = str(var["StatusMsg"]) 301 | if var["StatusMsg"] == '全部成交': 302 | self.workingOrderDict.pop(index) # 删除已成交 303 | # 保存委托信息到本地 304 | self.save_nontrade() 305 | # ---------------------------------------------------------------------- 306 | def getAccount(self): 307 | """查询账户""" 308 | self.td.qryAccount() 309 | # ---------------------------------------------------------------------- 310 | def getPosition(self): 311 | """查询持仓""" 312 | self.td.qryPosition() 313 | # ---------------------------------------------------------------------- 314 | def calculate_nav(self): 315 | """计算每日净值""" 316 | # 载入净值历史 317 | self.put_log('正在统计%s的净值' % self.userID) 318 | first = False 319 | try: 320 | path = os.path.join(ONEDRIVE_DIR, self.userID + '/nav.json') 321 | with open(path, 'r', encoding="utf-8") as f: 322 | na = json.load(f) 323 | except FileNotFoundError: 324 | na = [] 325 | first = True 326 | # 载入当日收盘权益 327 | ba = self.todayBalance 328 | # 计算净值 329 | currentDate = datetime.now().strftime('%Y-%m-%d') 330 | balance = ba[-1]["balance"] 331 | dw = ba[-1]["DepositWithdraw"] 332 | if first: 333 | changeValue = 0 334 | totalChange = 0 335 | else:# 去重复 336 | if na[-1]['date'] == currentDate: 337 | na.pop(-1) 338 | lastBalance = na[-1]['balance'] 339 | totalChange = na[-1]['totalChange'] 340 | changeValue = balance - lastBalance - dw 341 | totalChange += changeValue 342 | 343 | change = "涨" if changeValue >= 0 else "跌" 344 | changeValue = abs(changeValue) 345 | data = { 346 | "date": currentDate, 347 | "balance": balance, 348 | "change": change, 349 | "change_value": changeValue, 350 | "totalChange": totalChange, 351 | } 352 | na.append(data) 353 | # 保存净值历史 354 | self.nav = na 355 | self.save_nav() 356 | 357 | msg = '截至%s,您的账户权益为%d,较前一交易日%s%d,账户累计盈亏%d。' % (currentDate, balance, change, changeValue, totalChange) 358 | self.put_log(msg) 359 | 360 | def run_mainengine(config): 361 | import sys 362 | app = QApplication(sys.argv) 363 | connects = {} 364 | for i in range(len(config)): # 将多个账户登录分别实例化 365 | setting = config[i] 366 | connects[i] = MainEngine(setting) 367 | connects[i].login() 368 | app.exec_() 369 | 370 | class Watcher: 371 | '''守护进程''' 372 | def __init__(self): 373 | """constractor""" 374 | self.p = None # 子进程 375 | self.tradeDateList = [] # 交易日列表 376 | self.todaySetting = [] 377 | self.currentTime = datetime.now().time() # 当前时间 378 | self.currentDate = '' # 当前日期 379 | self.count = 0 # 循环计数 380 | self.config = [] # 账户信息 381 | self.load_tradedate() # 载入交易日列表 382 | self.load_config() # 载入账户信息 383 | self.loop() # 运行主循环 384 | 385 | def __del__(self): 386 | '''join process when exit''' 387 | if self.p: 388 | self.p.terminate() 389 | self.p.join() 390 | self.p = None 391 | 392 | def load_tradedate(self): 393 | """load tradeday from json""" 394 | with open('tradeDate.json', 'r', encoding="utf-8") as f: 395 | self.tradeDateList = json.load(f) 396 | 397 | def load_config(self): 398 | with open(CONFIG_FILE, 'r', encoding='utf-8') as f: 399 | self.config = json.load(f) 400 | # 创建新目录 401 | # savePath = os.path.abspath(ONEDRIVE_DIR) 402 | savePath = ONEDRIVE_DIR 403 | listPath = [x for x in os.listdir(savePath) if os.path.isdir(os.path.join(savePath, x))] 404 | for index in self.config: 405 | id = index['userID'] 406 | if id not in listPath: 407 | newPath = ''.join([savePath, id]) 408 | os.mkdir(newPath) 409 | print('正在为新用户{user}创建目录'.format(user=id)) 410 | 411 | def check_and_run(self): 412 | '''根据交易日列表管理子进程''' 413 | # 在交易日列表中查找当前日期 414 | i = 0 415 | while i < len(self.tradeDateList): 416 | if self.tradeDateList[i][0] == self.currentDate: 417 | n = i 418 | i = len(self.tradeDateList) 419 | i += 1 420 | # 交易日列表更新提醒 421 | try: 422 | if i - n < 10: 423 | print('交易日列表急需更新,否则将会在%s天后过期!' % (i-n)) 424 | # 如果交易日列表中找不到当前日期,则终止循环 425 | except: 426 | print('马上更新交易日列表!') 427 | return 428 | # 当天的开盘时间情况 429 | self.todaySetting = self.tradeDateList[n] 430 | # 运行 431 | self.run_account_updater() 432 | 433 | def run_account_updater(self): 434 | '''运行账户查询子进程''' 435 | running = False 436 | istradeday = self.todaySetting[2] 437 | open_at_night = self.todaySetting[3] 438 | open_at_morning = self.todaySetting[4] 439 | 440 | # 判断是否有开盘,且在开盘时间 441 | if istradeday and open_at_night and NIGHT_START < self.currentTime: 442 | running = True 443 | if open_at_morning and self.currentTime < MORNING_END:# 周六凌晨可能有开盘,因此不判断是否交易日 444 | running = True 445 | if istradeday and (DAY_START < self.currentTime < DAY_END): 446 | running = True 447 | 448 | # 交易时间启动子进程 449 | if running and self.p is None: 450 | log = ','.join([self.currentDate, self.currentTime.strftime('%H:%M:%S'), u'开始运行子进程: MultipleAccountUpdater']) 451 | print(log) 452 | self.p = multiprocessing.Process(target=run_mainengine, args=(self.config,)) 453 | self.p.start() 454 | 455 | # 非交易时间则退出子进程 456 | if not running and self.p is not None: 457 | log = ','.join([self.currentDate, self.currentTime.strftime('%H:%M:%S'), u'停止运行子进程: MultipleAccountUpdater']) 458 | print(log) 459 | self.p.terminate() 460 | self.p.join() 461 | self.p = None 462 | 463 | def loop(self): 464 | '''定时轮询''' 465 | print('启动中...') 466 | while True: 467 | # 更新当前时间 468 | self.currentDate = datetime.now().strftime('%Y%m%d') 469 | self.currentTime = datetime.now().time() 470 | self.check_and_run() 471 | sleep(9) 472 | 473 | # 直接运行脚本可以进行测试 474 | if __name__ == '__main__': 475 | watcher = Watcher() 476 | -------------------------------------------------------------------------------- /MultipleAccountUpdater/config.json: -------------------------------------------------------------------------------- 1 | [ 2 | 3 | { 4 | "name" : "test", 5 | "userID" : "", 6 | "brokerID" : "9999", 7 | "password" : "", 8 | "TdIp": "tcp://180.168.146.187:10001" 9 | } 10 | ] -------------------------------------------------------------------------------- /MultipleAccountUpdater/log/deleteme: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vvipi/VNPY_account_updater/669c3083232b4aeb68668b01c7c20f2d6be14b4c/MultipleAccountUpdater/log/deleteme -------------------------------------------------------------------------------- /MultipleAccountUpdater/py_ctp/__init__.py: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | """ 3 | 作者:vvipi 4 | """ -------------------------------------------------------------------------------- /MultipleAccountUpdater/py_ctp/ctp_api.py: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | """ 3 | CTP的底层接口来自VNPY,大佬bigtan帮助编译的python3版本 4 | """ 5 | from py_ctp.vnctptd import TdApi 6 | from py_ctp.eventEngine import * 7 | from py_ctp.ctp_data_type import * 8 | from time import sleep 9 | from datetime import datetime, time 10 | import random 11 | import os 12 | 13 | 14 | # 默认空值 15 | EMPTY_STRING = '' 16 | EMPTY_UNICODE = u'' 17 | EMPTY_INT = 0 18 | EMPTY_FLOAT = 0.0 19 | 20 | # 方向常量 21 | DIRECTION_NONE = u'无方向' 22 | DIRECTION_LONG = u'买入' 23 | DIRECTION_SHORT = u'卖出' 24 | DIRECTION_UNKNOWN = u'未知' 25 | DIRECTION_NET = u'净' 26 | DIRECTION_SELL = u'卖出' # IB接口 27 | DIRECTION_COVEREDSHORT = u'备兑空' # 证券期权 28 | 29 | # 开平常量 30 | OFFSET_NONE = u'无开平' 31 | OFFSET_OPEN = u'开仓' 32 | OFFSET_CLOSE = u'平仓' 33 | OFFSET_CLOSETODAY = u'平今' 34 | OFFSET_CLOSEYESTERDAY = u'平昨' 35 | OFFSET_UNKNOWN = u'未知' 36 | 37 | # 状态常量 38 | STATUS_NOTTRADED = u'未成交' 39 | STATUS_PARTTRADED = u'部分成交' 40 | STATUS_ALLTRADED = u'全部成交' 41 | STATUS_CANCELLED = u'已撤销' 42 | STATUS_REJECTED = u'拒单' 43 | STATUS_UNKNOWN = u'未知' 44 | 45 | # 合约类型常量 46 | PRODUCT_EQUITY = u'股票' 47 | PRODUCT_FUTURES = u'期货' 48 | PRODUCT_OPTION = u'期权' 49 | PRODUCT_INDEX = u'指数' 50 | PRODUCT_COMBINATION = u'组合' 51 | PRODUCT_FOREX = u'外汇' 52 | PRODUCT_UNKNOWN = u'未知' 53 | PRODUCT_SPOT = u'现货' 54 | PRODUCT_DEFER = u'延期' 55 | PRODUCT_NONE = '' 56 | 57 | # 价格类型常量 58 | PRICETYPE_LIMITPRICE = u'限价' 59 | PRICETYPE_MARKETPRICE = u'市价' 60 | PRICETYPE_FAK = u'FAK' 61 | PRICETYPE_FOK = u'FOK' 62 | 63 | # 期权类型 64 | OPTION_CALL = u'看涨期权' 65 | OPTION_PUT = u'看跌期权' 66 | 67 | # 交易所类型 68 | EXCHANGE_SSE = 'SSE' # 上交所 69 | EXCHANGE_SZSE = 'SZSE' # 深交所 70 | EXCHANGE_CFFEX = 'CFFEX' # 中金所 71 | EXCHANGE_SHFE = 'SHFE' # 上期所 72 | EXCHANGE_CZCE = 'CZCE' # 郑商所 73 | EXCHANGE_DCE = 'DCE' # 大商所 74 | EXCHANGE_SGE = 'SGE' # 上金所 75 | EXCHANGE_INE = 'INE' # 国际能源交易中心 76 | EXCHANGE_UNKNOWN = 'UNKNOWN'# 未知交易所 77 | EXCHANGE_NONE = '' # 空交易所 78 | 79 | 80 | # 货币类型 81 | CURRENCY_USD = 'USD' # 美元 82 | CURRENCY_CNY = 'CNY' # 人民币 83 | CURRENCY_HKD = 'HKD' # 港币 84 | CURRENCY_UNKNOWN = 'UNKNOWN' # 未知货币 85 | CURRENCY_NONE = '' # 空货币 86 | 87 | 88 | 89 | # 接口类型 90 | GATEWAYTYPE_FUTURES = 'futures' # 期货、期权、贵金属 91 | GATEWAYTYPE_DATA = 'data' # 数据(非交易) 92 | 93 | 94 | # 以下为一些VT类型和CTP类型的映射字典 95 | # 价格类型映射 96 | priceTypeMap = {} 97 | priceTypeMap[PRICETYPE_LIMITPRICE] = defineDict["THOST_FTDC_OPT_LimitPrice"] 98 | priceTypeMap[PRICETYPE_MARKETPRICE] = defineDict["THOST_FTDC_OPT_AnyPrice"] 99 | priceTypeMapReverse = {v: k for k, v in priceTypeMap.items()} 100 | 101 | # 方向类型映射 102 | directionMap = {} 103 | directionMap[DIRECTION_LONG] = defineDict['THOST_FTDC_D_Buy'] 104 | directionMap[DIRECTION_SHORT] = defineDict['THOST_FTDC_D_Sell'] 105 | directionMapReverse = {v: k for k, v in directionMap.items()} 106 | 107 | # 开平类型映射 108 | offsetMap = {} 109 | offsetMap[OFFSET_OPEN] = defineDict['THOST_FTDC_OF_Open'] 110 | offsetMap[OFFSET_CLOSE] = defineDict['THOST_FTDC_OF_Close'] 111 | offsetMap[OFFSET_CLOSETODAY] = defineDict['THOST_FTDC_OF_CloseToday'] 112 | offsetMap[OFFSET_CLOSEYESTERDAY] = defineDict['THOST_FTDC_OF_CloseYesterday'] 113 | offsetMapReverse = {v:k for k,v in offsetMap.items()} 114 | 115 | # 交易所类型映射 116 | exchangeMap = {} 117 | exchangeMap[EXCHANGE_CFFEX] = 'CFFEX' 118 | exchangeMap[EXCHANGE_SHFE] = 'SHFE' 119 | exchangeMap[EXCHANGE_CZCE] = 'CZCE' 120 | exchangeMap[EXCHANGE_DCE] = 'DCE' 121 | exchangeMap[EXCHANGE_SSE] = 'SSE' 122 | exchangeMap[EXCHANGE_UNKNOWN] = '' 123 | exchangeMapReverse = {v:k for k,v in exchangeMap.items()} 124 | 125 | # 持仓类型映射 126 | posiDirectionMap = {} 127 | posiDirectionMap[DIRECTION_NET] = defineDict["THOST_FTDC_PD_Net"] 128 | posiDirectionMap[DIRECTION_LONG] = defineDict["THOST_FTDC_PD_Long"] 129 | posiDirectionMap[DIRECTION_SHORT] = defineDict["THOST_FTDC_PD_Short"] 130 | posiDirectionMapReverse = {v:k for k,v in posiDirectionMap.items()} 131 | 132 | # 产品类型映射 133 | productClassMap = {} 134 | productClassMap[PRODUCT_FUTURES] = defineDict["THOST_FTDC_PC_Futures"] 135 | productClassMap[PRODUCT_OPTION] = defineDict["THOST_FTDC_PC_Options"] 136 | productClassMap[PRODUCT_COMBINATION] = defineDict["THOST_FTDC_PC_Combination"] 137 | productClassMapReverse = {v:k for k,v in productClassMap.items()} 138 | 139 | # 委托状态映射 140 | statusMap = {} 141 | statusMap[STATUS_ALLTRADED] = defineDict["THOST_FTDC_OST_AllTraded"] 142 | statusMap[STATUS_PARTTRADED] = defineDict["THOST_FTDC_OST_PartTradedQueueing"] 143 | statusMap[STATUS_NOTTRADED] = defineDict["THOST_FTDC_OST_NoTradeQueueing"] 144 | statusMap[STATUS_CANCELLED] = defineDict["THOST_FTDC_OST_Canceled"] 145 | statusMapReverse = {v:k for k,v in statusMap.items()} 146 | 147 | class CtaPositionData(object): 148 | """持仓数据类""" 149 | 150 | #---------------------------------------------------------------------- 151 | def __init__(self): 152 | """Constructor""" 153 | self.gatewayName = EMPTY_STRING # Gateway名称 154 | # 代码编号相关 155 | self.symbol = EMPTY_STRING # 合约代码 156 | self.exchange = EMPTY_STRING # 交易所代码 157 | self.vtSymbol = EMPTY_STRING # 合约在vt系统中的唯一代码,合约代码.交易所代码 158 | 159 | # 持仓相关 160 | self.direction = EMPTY_STRING # 持仓方向 161 | self.position = EMPTY_INT # 持仓量 162 | self.frozen = EMPTY_INT # 冻结数量 163 | self.price = EMPTY_FLOAT # 持仓均价 164 | self.vtPositionName = EMPTY_STRING # 持仓在vt系统中的唯一代码,通常是vtSymbol.方向 165 | self.ydPosition = EMPTY_INT # 昨持仓 166 | self.positionProfit = EMPTY_FLOAT # 持仓盈亏(盯) 167 | 168 | # 自行添加 169 | self.openPrice = EMPTY_FLOAT # 开仓均价 170 | self.openProfit = EMPTY_FLOAT # 开仓盈亏(浮) 171 | self.name = EMPTY_STRING # 合约名称 172 | ######################################################################## 173 | class CtpTdApi(TdApi): 174 | """CTP交易API实现""" 175 | 176 | #---------------------------------------------------------------------- 177 | def __init__(self, mainEngine, eventEngine): 178 | """API对象的初始化函数""" 179 | super(CtpTdApi, self).__init__() 180 | 181 | self.__eventEngine = eventEngine 182 | self.__mainEngine = mainEngine 183 | 184 | self.reqID = 0 # 操作请求编号 185 | self.orderRef = random.randrange(start=1000,stop=9000,step=random.randint(10,100) ) # 订单编号 186 | 187 | 188 | self.connectionStatus = False # 连接状态 189 | self.loginStatus = False # 登录状态 190 | 191 | self.userID = '' # 账号 192 | self.password = '' # 密码 193 | self.brokerID = '' # 经纪商代码 194 | self.address = '' # 服务器地址 195 | 196 | self.frontID = 0 # 前置机编号 197 | self.sessionID = 0 # 会话编号 198 | self.symbolExchangeDict = {} # 保存合约代码和交易所的映射关系 199 | self.symbolSizeDict = {} # 保存合约代码和合约大小的映射关系 200 | self.symbolNameDict = {} # 保存合约代码和合约名称的映射关系 201 | 202 | self.posDict = {} # 持仓缓存 203 | #---------------------------------------------------------------------- 204 | def put_start_event(self): # log事件注册 205 | event = Event(type_=EVENT_START + self.userID) 206 | event.dict_['data'] = 'start' 207 | self.__eventEngine.put(event) 208 | #---------------------------------------------------------------------- 209 | def put_log_event(self, log): # log事件注册 210 | event = Event(type_=EVENT_LOG) 211 | if self.userID not in log: 212 | event.dict_['log'] = self.userID + log 213 | else: 214 | event.dict_['log'] = log 215 | self.__eventEngine.put(event) 216 | #---------------------------------------------------------------------- 217 | def onRspSettlementInfoConfirm(self, data, error, n, last): 218 | """确认结算信息回报""" 219 | log = u'结算信息确认完成' 220 | self.put_log_event(log) 221 | self.put_start_event() 222 | # 查询合约代码 223 | self.reqID += 1 224 | self.reqQryInstrument({}, self.reqID) 225 | #---------------------------------------------------------------------- 226 | def onRspQryTradingAccount(self, data, error, n, last): 227 | """资金账户查询回报""" 228 | if error['ErrorID'] == 0: 229 | event = Event(type_=EVENT_ACCOUNT + self.userID) 230 | event.dict_['data'] = data 231 | self.__eventEngine.put(event) 232 | else: 233 | log = ('账户查询回报,错误代码:' +str(error['ErrorID']) + ', 错误信息:' +str(error['ErrorMsg'])) 234 | self.put_log_event(log) 235 | #---------------------------------------------------------------------- 236 | def onRspQryInvestorPosition(self, data, error, n, last): 237 | """持仓查询回报""" 238 | 239 | if not data['InstrumentID']: 240 | return 241 | if error['ErrorID'] == 0: 242 | # 读取交易所id|合约名称|方向|合约乘数 243 | ExchangeID = self.symbolExchangeDict.get(data['InstrumentID'], EXCHANGE_UNKNOWN) 244 | data['PosiDirection'] = posiDirectionMapReverse.get(data['PosiDirection'], '') 245 | 246 | # 获取持仓缓存对象 247 | posName = '.'.join([data['InstrumentID'], data['PosiDirection']]) 248 | 249 | if posName in self.posDict: 250 | pos = self.posDict[posName] 251 | else: 252 | pos = CtaPositionData() 253 | self.posDict[posName] = pos 254 | 255 | pos.gatewayName = 'CTP' 256 | pos.symbol = data['InstrumentID'] 257 | pos.vtSymbol = pos.symbol 258 | pos.direction = data['PosiDirection'] 259 | pos.vtPositionName = '.'.join([pos.vtSymbol, pos.direction]) 260 | pos.name = self.symbolNameDict.get(data['InstrumentID'], PRODUCT_UNKNOWN) 261 | 262 | # 针对上期所持仓的今昨分条返回(有昨仓、无今仓),读取昨仓数据.其他交易所只有一条,直接读取 263 | if (data['YdPosition'] and not data['TodayPosition']) and ExchangeID == EXCHANGE_SHFE: 264 | pos.ydPosition = data['Position'] 265 | # YdPosition字段存在一个问题,今天平昨仓不会减少这个字段的数量,改为从TodayPosition计算 266 | if ExchangeID != EXCHANGE_SHFE: 267 | pos.ydPosition = data['Position'] - data['TodayPosition'] 268 | 269 | # 计算成本 270 | size = self.symbolSizeDict[pos.symbol] 271 | cost = pos.price * pos.position * size 272 | openCost = pos.openPrice * pos.position * size 273 | 274 | # 汇总总仓 275 | pos.position += data['Position'] 276 | pos.positionProfit += data['PositionProfit'] 277 | # 计算开仓盈亏(浮) 278 | sign = 1 if pos.direction == DIRECTION_LONG else -1 279 | op = data["PositionProfit"] + (data["PositionCost"] - data["OpenCost"]) * sign 280 | pos.openProfit += op 281 | 282 | # 计算持仓均价和开仓均价 283 | if pos.position and size: 284 | pos.price = (cost + data['PositionCost']) / (pos.position * size) 285 | pos.openPrice = (openCost + data["OpenCost"]) / (pos.position * size) 286 | 287 | # 读取冻结 288 | if pos.direction == DIRECTION_LONG: 289 | pos.frozen += data['LongFrozen'] 290 | else: 291 | pos.frozen += data['ShortFrozen'] 292 | 293 | # 查询回报结束 294 | if last: 295 | # 遍历推送 296 | i = 0 297 | for pos in self.posDict.values(): 298 | # vnpy格式持仓事件 299 | i += 1 300 | lastPos = True if i >= len(self.posDict) else False 301 | 302 | event2 = Event(type_=EVENT_POSITION + self.userID) 303 | event2.dict_['data'] = pos 304 | event2.dict_['last'] = lastPos 305 | self.__eventEngine.put(event2) 306 | 307 | # 清空缓存 308 | self.posDict.clear() 309 | 310 | else: 311 | log = ('持仓查询回报,错误代码:' +str(error['ErrorID']) + ', 错误信息:' +str(error['ErrorMsg'])) 312 | self.put_log_event(log) 313 | #---------------------------------------------------------------------- 314 | def onRtnOrder(self, data): 315 | """报单回报""" 316 | 317 | # 更新最大报单编号 318 | newref = data['OrderRef'] 319 | self.orderRef = max(self.orderRef, int(newref)) 320 | 321 | 322 | # 方向 323 | data['Direction'] = directionMapReverse.get(data['Direction'], DIRECTION_UNKNOWN) 324 | 325 | # 开平 326 | data['CombOffsetFlag'] = offsetMapReverse.get(data['CombOffsetFlag'], OFFSET_UNKNOWN) 327 | 328 | # 状态 329 | data['OrderStatus'] = statusMapReverse.get(data['OrderStatus'], STATUS_UNKNOWN) 330 | 331 | # 单客户报单事件 332 | event1 = Event(type_=(EVENT_ORDER + self.userID)) 333 | event1.dict_['data'] = data 334 | self.__eventEngine.put(event1) 335 | #---------------------------------------------------------------------- 336 | def onFrontConnected(self): 337 | """服务器连接""" 338 | self.connectionStatus = True 339 | 340 | log = u'交易服务器连接成功' 341 | self.put_log_event(log) 342 | 343 | self.login() 344 | 345 | #---------------------------------------------------------------------- 346 | def onFrontDisconnected(self, n): 347 | """服务器断开""" 348 | self.connectionStatus = False 349 | self.loginStatus = False 350 | 351 | log = u'交易服务器连接断开' 352 | self.put_log_event(log) 353 | 354 | #---------------------------------------------------------------------- 355 | def onRspUserLogin(self, data, error, n, last): 356 | """登陆回报""" 357 | # 如果登录成功,推送日志信息 358 | if error['ErrorID'] == 0: 359 | self.frontID = str(data['FrontID']) 360 | self.sessionID = str(data['SessionID']) 361 | self.loginStatus = True 362 | 363 | log = data['UserID'] + u'交易服务器登录完成' 364 | self.put_log_event(log) 365 | 366 | # 确认结算信息 367 | req = {} 368 | req['BrokerID'] = self.brokerID 369 | req['InvestorID'] = self.userID 370 | self.reqID += 1 371 | self.reqSettlementInfoConfirm(req, self.reqID) 372 | 373 | # 否则,推送错误信息 374 | else: 375 | log = error['ErrorMsg'] 376 | self.put_log_event(log) 377 | 378 | #---------------------------------------------------------------------- 379 | def onRspUserLogout(self, data, error, n, last): 380 | """登出回报""" 381 | # 如果登出成功,推送日志信息 382 | if error['ErrorID'] == 0: 383 | self.loginStatus = False 384 | 385 | log = u'交易服务器登出完成' 386 | self.put_log_event(log) 387 | 388 | # 否则,推送错误信息 389 | else: 390 | log = error['ErrorMsg'] 391 | self.put_log_event(log) 392 | #---------------------------------------------------------------------- 393 | def connect(self, userID, password, brokerID, address): 394 | """初始化连接""" 395 | self.userID = userID # 账号 396 | self.password = password # 密码 397 | self.brokerID = brokerID # 经纪商代码 398 | self.address = address # 服务器地址 399 | 400 | # 如果尚未建立服务器连接,则进行连接 401 | if not self.connectionStatus: 402 | # 创建C++环境中的API对象,这里传入的参数是需要用来保存.con文件的文件夹路径 403 | path = os.getcwd() + '/temp/' 404 | if not os.path.exists(path): 405 | os.makedirs(path) 406 | self.createFtdcTraderApi(path) 407 | 408 | # 注册服务器地址 409 | self.registerFront(self.address) 410 | 411 | # 初始化连接,成功会调用onFrontConnected 412 | self.init() 413 | 414 | # 若已经连接但尚未登录,则进行登录 415 | else: 416 | if not self.loginStatus: 417 | self.login() 418 | 419 | #---------------------------------------------------------------------- 420 | def login(self): 421 | """连接服务器""" 422 | # 如果填入了用户名密码等,则登录 423 | if self.userID and self.password and self.brokerID: 424 | req = {} 425 | req['UserID'] = self.userID 426 | req['Password'] = self.password 427 | req['BrokerID'] = self.brokerID 428 | self.reqID += 1 429 | self.reqUserLogin(req, self.reqID) 430 | #---------------------------------------------------------------------- 431 | def qryAccount(self): 432 | """查询账户""" 433 | self.reqID += 1 434 | self.reqQryTradingAccount({}, self.reqID) 435 | #---------------------------------------------------------------------- 436 | def qryPosition(self): 437 | """查询持仓""" 438 | self.reqID += 1 439 | req = {} 440 | req['BrokerID'] = self.brokerID 441 | req['InvestorID'] = self.userID 442 | self.reqQryInvestorPosition(req, self.reqID) 443 | #---------------------------------------------------------------------- 444 | def sendOrder(self, orderReq): 445 | """发单""" 446 | return 447 | #---------------------------------------------------------------------- 448 | def close(self): 449 | """关闭""" 450 | self.exit() 451 | 452 | #---------------------------------------------------------------------- 453 | def onRspQryInstrument(self, data, error, n, last): 454 | """ 455 | 合约查询回报 456 | 由于该回报的推送速度极快,因此不适合全部存入队列中处理, 457 | 选择先储存在一个本地字典中,全部收集完毕后再推送到队列中 458 | (由于耗时过长目前使用其他进程读取) 459 | """ 460 | if error['ErrorID'] == 0: 461 | self.symbolExchangeDict[data['InstrumentID']] = data['ExchangeID'] # 合约代码和交易所的映射关系 462 | self.symbolSizeDict[data['InstrumentID']] = data['VolumeMultiple'] # 合约代码和合约乘数映射关系 463 | self.symbolNameDict[data['InstrumentID']] = data['InstrumentName'] # 合约代码和合约名称映射关系 464 | 465 | event = Event(type_=EVENT_INSTRUMENT) 466 | event.dict_['data'] = data 467 | event.dict_['last'] = last 468 | self.__eventEngine.put(event) 469 | 470 | else: 471 | log = '合约投资者回报,错误代码:' + str(error['ErrorID']) + ', 错误信息:' + str(error['ErrorMsg']) 472 | self.put_log_event(log) 473 | 474 | #---------------------------------------------------------------------- 475 | def onRspQryDepthMarketData(self, data, error, n, last): 476 | # 常规行情事件,查询合约截面数据的回报 477 | pass 478 | 479 | #---------------------------------------------------------------------- 480 | def onRspOrderInsert(self, data, error, n, last): 481 | """发单错误(柜台)""" 482 | pass 483 | 484 | #---------------------------------------------------------------------- 485 | def onRspOrderAction(self, data, error, n, last): 486 | """撤单错误(柜台)""" 487 | pass 488 | 489 | #---------------------------------------------------------------------- 490 | def onRspError(self, error, n, last): 491 | """错误回报""" 492 | pass 493 | 494 | 495 | #---------------------------------------------------------------------- 496 | def onRtnTrade(self, data): 497 | """成交回报""" 498 | return 499 | 500 | #---------------------------------------------------------------------- 501 | def onErrRtnOrderInsert(self, data, error): 502 | """发单错误回报(交易所)""" 503 | log = error['ErrorMsg'] 504 | self.put_log_event(log) 505 | 506 | #---------------------------------------------------------------------- 507 | def onErrRtnOrderAction(self, data, error): 508 | """撤单错误回报(交易所)""" 509 | pass 510 | 511 | #---------------------------------------------------------------------- 512 | def onHeartBeatWarning(self, n): 513 | """""" 514 | pass 515 | 516 | #---------------------------------------------------------------------- 517 | def onRspAuthenticate(self, data, error, n, last): 518 | """""" 519 | pass 520 | 521 | #---------------------------------------------------------------------- 522 | def onRspRemoveParkedOrder(self, data, error, n, last): 523 | """""" 524 | pass 525 | 526 | #---------------------------------------------------------------------- 527 | def onRspQueryMaxOrderVolume(self, data, error, n, last): 528 | """""" 529 | pass 530 | 531 | #---------------------------------------------------------------------- 532 | def onRspRemoveParkedOrderAction(self, data, error, n, last): 533 | """""" 534 | pass 535 | 536 | #---------------------------------------------------------------------- 537 | def onRspUserPasswordUpdate(self, data, error, n, last): 538 | """""" 539 | pass 540 | 541 | #---------------------------------------------------------------------- 542 | def onRspTradingAccountPasswordUpdate(self, data, error, n, last): 543 | """""" 544 | pass 545 | 546 | #---------------------------------------------------------------------- 547 | def onRspParkedOrderInsert(self, data, error, n, last): 548 | """""" 549 | pass 550 | 551 | #---------------------------------------------------------------------- 552 | def onRspParkedOrderAction(self, data, error, n, last): 553 | """""" 554 | pass 555 | 556 | #---------------------------------------------------------------------- 557 | def onRspExecOrderInsert(self, data, error, n, last): 558 | """""" 559 | pass 560 | 561 | #---------------------------------------------------------------------- 562 | def onRspExecOrderAction(self, data, error, n, last): 563 | """""" 564 | pass 565 | 566 | #---------------------------------------------------------------------- 567 | def onRspForQuoteInsert(self, data, error, n, last): 568 | """""" 569 | pass 570 | 571 | #---------------------------------------------------------------------- 572 | def onRspQuoteInsert(self, data, error, n, last): 573 | """""" 574 | pass 575 | 576 | #---------------------------------------------------------------------- 577 | def onRspQuoteAction(self, data, error, n, last): 578 | """""" 579 | pass 580 | 581 | #---------------------------------------------------------------------- 582 | def onRspLockInsert(self, data, error, n, last): 583 | """""" 584 | pass 585 | 586 | #---------------------------------------------------------------------- 587 | def onRspCombActionInsert(self, data, error, n, last): 588 | """""" 589 | pass 590 | 591 | #---------------------------------------------------------------------- 592 | def onRspQryOrder(self, data, error, n, last): 593 | """""" 594 | pass 595 | 596 | #---------------------------------------------------------------------- 597 | def onRspQryTrade(self, data, error, n, last): 598 | """""" 599 | pass 600 | 601 | 602 | #---------------------------------------------------------------------- 603 | def onRspQryInvestor(self, data, error, n, last): 604 | """""" 605 | pass 606 | 607 | #---------------------------------------------------------------------- 608 | def onRspQryTradingCode(self, data, error, n, last): 609 | """""" 610 | pass 611 | 612 | #---------------------------------------------------------------------- 613 | def onRspQryInstrumentMarginRate(self, data, error, n, last): 614 | """""" 615 | pass 616 | 617 | #---------------------------------------------------------------------- 618 | def onRspQryInstrumentCommissionRate(self, data, error, n, last): 619 | """""" 620 | pass 621 | 622 | #---------------------------------------------------------------------- 623 | def onRspQryExchange(self, data, error, n, last): 624 | """""" 625 | pass 626 | 627 | #---------------------------------------------------------------------- 628 | def onRspQryProduct(self, data, error, n, last): 629 | """""" 630 | pass 631 | 632 | #---------------------------------------------------------------------- 633 | def onRspQrySettlementInfo(self, data, error, n, last): 634 | """""" 635 | pass 636 | 637 | #---------------------------------------------------------------------- 638 | def onRspQryTransferBank(self, data, error, n, last): 639 | """""" 640 | pass 641 | 642 | #---------------------------------------------------------------------- 643 | def onRspQryInvestorPositionDetail(self, data, error, n, last): 644 | """""" 645 | pass 646 | 647 | #---------------------------------------------------------------------- 648 | def onRspQryNotice(self, data, error, n, last): 649 | """""" 650 | pass 651 | 652 | #---------------------------------------------------------------------- 653 | def onRspQrySettlementInfoConfirm(self, data, error, n, last): 654 | """""" 655 | pass 656 | 657 | #---------------------------------------------------------------------- 658 | def onRspQryInvestorPositionCombineDetail(self, data, error, n, last): 659 | """""" 660 | pass 661 | 662 | #---------------------------------------------------------------------- 663 | def onRspQryCFMMCTradingAccountKey(self, data, error, n, last): 664 | """""" 665 | pass 666 | 667 | #---------------------------------------------------------------------- 668 | def onRspQryEWarrantOffset(self, data, error, n, last): 669 | """""" 670 | pass 671 | 672 | #---------------------------------------------------------------------- 673 | def onRspQryInvestorProductGroupMargin(self, data, error, n, last): 674 | """""" 675 | pass 676 | 677 | #---------------------------------------------------------------------- 678 | def onRspQryExchangeMarginRate(self, data, error, n, last): 679 | """""" 680 | pass 681 | 682 | #---------------------------------------------------------------------- 683 | def onRspQryExchangeMarginRateAdjust(self, data, error, n, last): 684 | """""" 685 | pass 686 | 687 | #---------------------------------------------------------------------- 688 | def onRspQryExchangeRate(self, data, error, n, last): 689 | """""" 690 | pass 691 | 692 | #---------------------------------------------------------------------- 693 | def onRspQrySecAgentACIDMap(self, data, error, n, last): 694 | """""" 695 | pass 696 | 697 | #---------------------------------------------------------------------- 698 | def onRspQryProductExchRate(self, data, error, n, last): 699 | """""" 700 | pass 701 | 702 | #---------------------------------------------------------------------- 703 | def onRspQryProductGroup(self, data, error, n, last): 704 | """""" 705 | pass 706 | 707 | #---------------------------------------------------------------------- 708 | def onRspQryOptionInstrTradeCost(self, data, error, n, last): 709 | """""" 710 | pass 711 | 712 | #---------------------------------------------------------------------- 713 | def onRspQryOptionInstrCommRate(self, data, error, n, last): 714 | """""" 715 | pass 716 | 717 | #---------------------------------------------------------------------- 718 | def onRspQryExecOrder(self, data, error, n, last): 719 | """""" 720 | pass 721 | 722 | #---------------------------------------------------------------------- 723 | def onRspQryForQuote(self, data, error, n, last): 724 | """""" 725 | pass 726 | 727 | #---------------------------------------------------------------------- 728 | def onRspQryQuote(self, data, error, n, last): 729 | """""" 730 | pass 731 | 732 | #---------------------------------------------------------------------- 733 | def onRspQryLock(self, data, error, n, last): 734 | """""" 735 | pass 736 | 737 | #---------------------------------------------------------------------- 738 | def onRspQryLockPosition(self, data, error, n, last): 739 | """""" 740 | pass 741 | 742 | #---------------------------------------------------------------------- 743 | def onRspQryInvestorLevel(self, data, error, n, last): 744 | """""" 745 | pass 746 | 747 | #---------------------------------------------------------------------- 748 | def onRspQryExecFreeze(self, data, error, n, last): 749 | """""" 750 | pass 751 | 752 | #---------------------------------------------------------------------- 753 | def onRspQryCombInstrumentGuard(self, data, error, n, last): 754 | """""" 755 | pass 756 | 757 | #---------------------------------------------------------------------- 758 | def onRspQryCombAction(self, data, error, n, last): 759 | """""" 760 | pass 761 | 762 | #---------------------------------------------------------------------- 763 | def onRspQryTransferSerial(self, data, error, n, last): 764 | """""" 765 | pass 766 | 767 | #---------------------------------------------------------------------- 768 | def onRspQryAccountregister(self, data, error, n, last): 769 | """""" 770 | pass 771 | 772 | 773 | #---------------------------------------------------------------------- 774 | def onRtnInstrumentStatus(self, data): 775 | """""" 776 | pass 777 | 778 | #---------------------------------------------------------------------- 779 | def onRtnTradingNotice(self, data): 780 | """""" 781 | pass 782 | 783 | #---------------------------------------------------------------------- 784 | def onRtnErrorConditionalOrder(self, data): 785 | """""" 786 | pass 787 | 788 | #---------------------------------------------------------------------- 789 | def onRtnExecOrder(self, data): 790 | """""" 791 | pass 792 | 793 | #---------------------------------------------------------------------- 794 | def onErrRtnExecOrderInsert(self, data, error): 795 | """""" 796 | pass 797 | 798 | #---------------------------------------------------------------------- 799 | def onErrRtnExecOrderAction(self, data, error): 800 | """""" 801 | pass 802 | 803 | #---------------------------------------------------------------------- 804 | def onErrRtnForQuoteInsert(self, data, error): 805 | """""" 806 | pass 807 | 808 | #---------------------------------------------------------------------- 809 | def onRtnQuote(self, data): 810 | """""" 811 | pass 812 | 813 | #---------------------------------------------------------------------- 814 | def onErrRtnQuoteInsert(self, data, error): 815 | """""" 816 | pass 817 | 818 | #---------------------------------------------------------------------- 819 | def onErrRtnQuoteAction(self, data, error): 820 | """""" 821 | pass 822 | 823 | #---------------------------------------------------------------------- 824 | def onRtnForQuoteRsp(self, data): 825 | """""" 826 | pass 827 | 828 | #---------------------------------------------------------------------- 829 | def onRtnCFMMCTradingAccountToken(self, data): 830 | """""" 831 | pass 832 | 833 | #---------------------------------------------------------------------- 834 | def onRtnLock(self, data): 835 | """""" 836 | pass 837 | 838 | #---------------------------------------------------------------------- 839 | def onErrRtnLockInsert(self, data, error): 840 | """""" 841 | pass 842 | 843 | #---------------------------------------------------------------------- 844 | def onRtnCombAction(self, data): 845 | """""" 846 | pass 847 | 848 | #---------------------------------------------------------------------- 849 | def onErrRtnCombActionInsert(self, data, error): 850 | """""" 851 | pass 852 | 853 | #---------------------------------------------------------------------- 854 | def onRspQryContractBank(self, data, error, n, last): 855 | """""" 856 | pass 857 | 858 | #---------------------------------------------------------------------- 859 | def onRspQryParkedOrder(self, data, error, n, last): 860 | """""" 861 | pass 862 | 863 | #---------------------------------------------------------------------- 864 | def onRspQryParkedOrderAction(self, data, error, n, last): 865 | """""" 866 | pass 867 | 868 | #---------------------------------------------------------------------- 869 | def onRspQryTradingNotice(self, data, error, n, last): 870 | """""" 871 | pass 872 | 873 | #---------------------------------------------------------------------- 874 | def onRspQryBrokerTradingParams(self, data, error, n, last): 875 | """""" 876 | pass 877 | 878 | #---------------------------------------------------------------------- 879 | def onRspQryBrokerTradingAlgos(self, data, error, n, last): 880 | """""" 881 | pass 882 | 883 | #---------------------------------------------------------------------- 884 | def onRspQueryCFMMCTradingAccountToken(self, data, error, n, last): 885 | """""" 886 | pass 887 | 888 | #---------------------------------------------------------------------- 889 | def onRtnFromBankToFutureByBank(self, data): 890 | """""" 891 | pass 892 | 893 | #---------------------------------------------------------------------- 894 | def onRtnFromFutureToBankByBank(self, data): 895 | """""" 896 | pass 897 | 898 | #---------------------------------------------------------------------- 899 | def onRtnRepealFromBankToFutureByBank(self, data): 900 | """""" 901 | pass 902 | 903 | #---------------------------------------------------------------------- 904 | def onRtnRepealFromFutureToBankByBank(self, data): 905 | """""" 906 | pass 907 | 908 | #---------------------------------------------------------------------- 909 | def onRtnFromBankToFutureByFuture(self, data): 910 | """""" 911 | pass 912 | 913 | #---------------------------------------------------------------------- 914 | def onRtnFromFutureToBankByFuture(self, data): 915 | """""" 916 | pass 917 | 918 | #---------------------------------------------------------------------- 919 | def onRtnRepealFromBankToFutureByFutureManual(self, data): 920 | """""" 921 | pass 922 | 923 | #---------------------------------------------------------------------- 924 | def onRtnRepealFromFutureToBankByFutureManual(self, data): 925 | """""" 926 | pass 927 | 928 | #---------------------------------------------------------------------- 929 | def onRtnQueryBankBalanceByFuture(self, data): 930 | """""" 931 | pass 932 | 933 | #---------------------------------------------------------------------- 934 | def onErrRtnBankToFutureByFuture(self, data, error): 935 | """""" 936 | pass 937 | 938 | #---------------------------------------------------------------------- 939 | def onErrRtnFutureToBankByFuture(self, data, error): 940 | """""" 941 | pass 942 | 943 | #---------------------------------------------------------------------- 944 | def onErrRtnRepealBankToFutureByFutureManual(self, data, error): 945 | """""" 946 | pass 947 | 948 | #---------------------------------------------------------------------- 949 | def onErrRtnRepealFutureToBankByFutureManual(self, data, error): 950 | """""" 951 | pass 952 | 953 | #---------------------------------------------------------------------- 954 | def onErrRtnQueryBankBalanceByFuture(self, data, error): 955 | """""" 956 | pass 957 | 958 | #---------------------------------------------------------------------- 959 | def onRtnRepealFromBankToFutureByFuture(self, data): 960 | """""" 961 | pass 962 | 963 | #---------------------------------------------------------------------- 964 | def onRtnRepealFromFutureToBankByFuture(self, data): 965 | """""" 966 | pass 967 | 968 | #---------------------------------------------------------------------- 969 | def onRspFromBankToFutureByFuture(self, data, error, n, last): 970 | """""" 971 | pass 972 | 973 | #---------------------------------------------------------------------- 974 | def onRspFromFutureToBankByFuture(self, data, error, n, last): 975 | """""" 976 | pass 977 | 978 | #---------------------------------------------------------------------- 979 | def onRspQueryBankAccountMoneyByFuture(self, data, error, n, last): 980 | """""" 981 | pass 982 | 983 | #---------------------------------------------------------------------- 984 | def onRtnOpenAccountByBank(self, data): 985 | """""" 986 | pass 987 | 988 | #---------------------------------------------------------------------- 989 | def onRtnCancelAccountByBank(self, data): 990 | """""" 991 | pass 992 | 993 | #---------------------------------------------------------------------- 994 | def onRtnChangeAccountByBank(self, data): 995 | """""" 996 | pass 997 | 998 | 999 | 1000 | -------------------------------------------------------------------------------- /MultipleAccountUpdater/py_ctp/eventEngine.py: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | 3 | # 系统模块 4 | from queue import Queue, Empty 5 | from threading import Thread 6 | from collections import defaultdict 7 | from time import sleep 8 | # 第三方模块 9 | #from PyQt4.QtCore import QTimer 10 | 11 | # 自己开发的模块 12 | #from eventType import * 13 | EVENT_TIMER = 'eTimer' 14 | EVENT_ACCOUNT = 'eAccount' 15 | EVENT_POSITION = 'ePosition' 16 | EVENT_ORDER = 'eOrder' 17 | EVENT_LOG = 'eLog' 18 | EVENT_START = 'eStart' 19 | 20 | ######################################################################## 21 | class EventEngine(object): 22 | """ 23 | 计时器使用python线程的事件驱动引擎 24 | """ 25 | 26 | #---------------------------------------------------------------------- 27 | def __init__(self): 28 | """初始化事件引擎""" 29 | # 事件队列 30 | self.__queue = Queue() 31 | 32 | # 事件引擎开关 33 | self.__active = False 34 | 35 | # 事件处理线程 36 | self.__thread = Thread(target = self.__run) 37 | 38 | # 计时器,用于触发计时器事件 39 | self.__timer = Thread(target = self.__runTimer) 40 | self.__timerActive = False # 计时器工作状态 41 | self.__timerSleep = 1 # 计时器触发间隔(默认1秒) 42 | 43 | # 这里的__handlers是一个字典,用来保存对应的事件调用关系 44 | # 其中每个键对应的值是一个列表,列表中保存了对该事件进行监听的函数功能 45 | self.__handlers = defaultdict(list) 46 | 47 | # __generalHandlers是一个列表,用来保存通用回调函数(所有事件均调用) 48 | self.__generalHandlers = [] 49 | 50 | #---------------------------------------------------------------------- 51 | def __run(self): 52 | """引擎运行""" 53 | while self.__active == True: 54 | try: 55 | event = self.__queue.get(block = True, timeout = 1) # 获取事件的阻塞时间设为1秒 56 | self.__process(event) 57 | except Empty: 58 | pass 59 | 60 | #---------------------------------------------------------------------- 61 | def __process(self, event): 62 | """处理事件""" 63 | # 检查是否存在对该事件进行监听的处理函数 64 | if event.type_ in self.__handlers: 65 | # 若存在,则按顺序将事件传递给处理函数执行 66 | [handler(event) for handler in self.__handlers[event.type_]] 67 | 68 | # 以上语句为Python列表解析方式的写法,对应的常规循环写法为: 69 | #for handler in self.__handlers[event.type_]: 70 | #handler(event) 71 | 72 | # 调用通用处理函数进行处理 73 | if self.__generalHandlers: 74 | [handler(event) for handler in self.__generalHandlers] 75 | 76 | #---------------------------------------------------------------------- 77 | def __runTimer(self): 78 | """运行在计时器线程中的循环函数""" 79 | while self.__timerActive: 80 | # 创建计时器事件 81 | event = Event(type_=EVENT_TIMER) 82 | 83 | # 向队列中存入计时器事件 84 | self.put(event) 85 | 86 | # 等待 87 | sleep(self.__timerSleep) 88 | 89 | #---------------------------------------------------------------------- 90 | def start(self, timer=True): 91 | """ 92 | 引擎启动 93 | timer:是否要启动计时器 94 | """ 95 | # 将引擎设为启动 96 | self.__active = True 97 | 98 | # 启动事件处理线程 99 | self.__thread.start() 100 | 101 | # 启动计时器,计时器事件间隔默认设定为1秒 102 | if timer: 103 | self.__timerActive = True 104 | self.__timer.start() 105 | 106 | #---------------------------------------------------------------------- 107 | def stop(self): 108 | """停止引擎""" 109 | # 将引擎设为停止 110 | self.__active = False 111 | 112 | # 停止计时器 113 | self.__timerActive = False 114 | self.__timer.join() 115 | 116 | # 等待事件处理线程退出 117 | self.__thread.join() 118 | 119 | #---------------------------------------------------------------------- 120 | def register(self, type_, handler): 121 | """注册事件处理函数监听""" 122 | # 尝试获取该事件类型对应的处理函数列表,若无defaultDict会自动创建新的list 123 | handlerList = self.__handlers[type_] 124 | 125 | # 若要注册的处理器不在该事件的处理器列表中,则注册该事件 126 | if handler not in handlerList: 127 | handlerList.append(handler) 128 | 129 | #---------------------------------------------------------------------- 130 | def unregister(self, type_, handler): 131 | """注销事件处理函数监听""" 132 | # 尝试获取该事件类型对应的处理函数列表,若无则忽略该次注销请求 133 | handlerList = self.__handlers[type_] 134 | 135 | # 如果该函数存在于列表中,则移除 136 | if handler in handlerList: 137 | handlerList.remove(handler) 138 | 139 | # 如果函数列表为空,则从引擎中移除该事件类型 140 | if not handlerList: 141 | del self.__handlers[type_] 142 | 143 | #---------------------------------------------------------------------- 144 | def put(self, event): 145 | """向事件队列中存入事件""" 146 | self.__queue.put(event) 147 | 148 | #---------------------------------------------------------------------- 149 | def registerGeneralHandler(self, handler): 150 | """注册通用事件处理函数监听""" 151 | if handler not in self.__generalHandlers: 152 | self.__generalHandlers.append(handler) 153 | 154 | #---------------------------------------------------------------------- 155 | def unregisterGeneralHandler(self, handler): 156 | """注销通用事件处理函数监听""" 157 | if handler in self.__generalHandlers: 158 | self.__generalHandlers.remove(handler) 159 | ######################################################################## 160 | class Event: 161 | """事件对象""" 162 | 163 | #---------------------------------------------------------------------- 164 | def __init__(self, type_=None): 165 | """Constructor""" 166 | self.type_ = type_ # 事件类型 167 | self.dict_ = {} # 字典用于保存具体的事件数据 168 | 169 | 170 | #---------------------------------------------------------------------- 171 | def test(): 172 | """测试函数""" 173 | import sys 174 | from datetime import datetime 175 | # from PyQt4.QtCore import QCoreApplication 176 | 177 | def simpletest(event): 178 | print(u'处理每秒触发的计时器事件:%s' % str(datetime.now())) 179 | 180 | # app = QCoreApplication(sys.argv) 181 | 182 | ee = EventEngine() 183 | ee.register(EVENT_TIMER, simpletest) 184 | ee.start() 185 | 186 | # app.exec_() 187 | 188 | 189 | # 直接运行脚本可以进行测试 190 | if __name__ == '__main__': 191 | test() -------------------------------------------------------------------------------- /MultipleAccountUpdater/py_ctp/thosttraderapi.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vvipi/VNPY_account_updater/669c3083232b4aeb68668b01c7c20f2d6be14b4c/MultipleAccountUpdater/py_ctp/thosttraderapi.dll -------------------------------------------------------------------------------- /MultipleAccountUpdater/py_ctp/vnctptd.pyd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vvipi/VNPY_account_updater/669c3083232b4aeb68668b01c7c20f2d6be14b4c/MultipleAccountUpdater/py_ctp/vnctptd.pyd -------------------------------------------------------------------------------- /MultipleAccountUpdater/tradeDate.json: -------------------------------------------------------------------------------- 1 | [ 2 | [ 3 | "20181201", 4 | "6", 5 | false, 6 | false, 7 | true 8 | ], 9 | [ 10 | "20181202", 11 | "0", 12 | false, 13 | false, 14 | false 15 | ], 16 | [ 17 | "20181203", 18 | "1", 19 | true, 20 | true, 21 | false 22 | ], 23 | [ 24 | "20181204", 25 | "2", 26 | true, 27 | true, 28 | true 29 | ], 30 | [ 31 | "20181205", 32 | "3", 33 | true, 34 | true, 35 | true 36 | ], 37 | [ 38 | "20181206", 39 | "4", 40 | true, 41 | true, 42 | true 43 | ], 44 | [ 45 | "20181207", 46 | "5", 47 | true, 48 | true, 49 | true 50 | ], 51 | [ 52 | "20181208", 53 | "6", 54 | false, 55 | false, 56 | true 57 | ], 58 | [ 59 | "20181209", 60 | "0", 61 | false, 62 | false, 63 | false 64 | ], 65 | [ 66 | "20181210", 67 | "1", 68 | true, 69 | true, 70 | false 71 | ], 72 | [ 73 | "20181211", 74 | "2", 75 | true, 76 | true, 77 | true 78 | ], 79 | [ 80 | "20181212", 81 | "3", 82 | true, 83 | true, 84 | true 85 | ], 86 | [ 87 | "20181213", 88 | "4", 89 | true, 90 | true, 91 | true 92 | ], 93 | [ 94 | "20181214", 95 | "5", 96 | true, 97 | true, 98 | true 99 | ], 100 | [ 101 | "20181215", 102 | "6", 103 | false, 104 | false, 105 | true 106 | ], 107 | [ 108 | "20181216", 109 | "0", 110 | false, 111 | false, 112 | false 113 | ], 114 | [ 115 | "20181217", 116 | "1", 117 | true, 118 | true, 119 | false 120 | ], 121 | [ 122 | "20181218", 123 | "2", 124 | true, 125 | true, 126 | true 127 | ], 128 | [ 129 | "20181219", 130 | "3", 131 | true, 132 | true, 133 | true 134 | ], 135 | [ 136 | "20181220", 137 | "4", 138 | true, 139 | true, 140 | true 141 | ], 142 | [ 143 | "20181221", 144 | "5", 145 | true, 146 | true, 147 | true 148 | ], 149 | [ 150 | "20181222", 151 | "6", 152 | false, 153 | false, 154 | true 155 | ], 156 | [ 157 | "20181223", 158 | "0", 159 | false, 160 | false, 161 | false 162 | ], 163 | [ 164 | "20181224", 165 | "1", 166 | true, 167 | true, 168 | false 169 | ], 170 | [ 171 | "20181225", 172 | "2", 173 | true, 174 | true, 175 | true 176 | ], 177 | [ 178 | "20181226", 179 | "3", 180 | true, 181 | true, 182 | true 183 | ], 184 | [ 185 | "20181227", 186 | "4", 187 | true, 188 | true, 189 | true 190 | ], 191 | [ 192 | "20181228", 193 | "5", 194 | true, 195 | false, 196 | true 197 | ], 198 | [ 199 | "20181229", 200 | "6", 201 | false, 202 | false, 203 | false 204 | ], 205 | [ 206 | "20181230", 207 | "0", 208 | false, 209 | false, 210 | false 211 | ], 212 | [ 213 | "20181231", 214 | "1", 215 | false, 216 | false, 217 | false 218 | ], 219 | [ 220 | "20190101", 221 | "2", 222 | false, 223 | false, 224 | false 225 | ], 226 | [ 227 | "20190102", 228 | "3", 229 | true, 230 | true, 231 | false 232 | ], 233 | [ 234 | "20190103", 235 | "4", 236 | true, 237 | true, 238 | true 239 | ], 240 | [ 241 | "20190104", 242 | "5", 243 | true, 244 | true, 245 | true 246 | ], 247 | [ 248 | "20190105", 249 | "6", 250 | false, 251 | false, 252 | true 253 | ], 254 | [ 255 | "20190106", 256 | "0", 257 | false, 258 | false, 259 | false 260 | ], 261 | [ 262 | "20190107", 263 | "1", 264 | true, 265 | true, 266 | false 267 | ], 268 | [ 269 | "20190108", 270 | "2", 271 | true, 272 | true, 273 | true 274 | ], 275 | [ 276 | "20190109", 277 | "3", 278 | true, 279 | true, 280 | true 281 | ], 282 | [ 283 | "20190110", 284 | "4", 285 | true, 286 | true, 287 | true 288 | ], 289 | [ 290 | "20190111", 291 | "5", 292 | true, 293 | true, 294 | true 295 | ], 296 | [ 297 | "20190112", 298 | "6", 299 | false, 300 | false, 301 | true 302 | ], 303 | [ 304 | "20190113", 305 | "0", 306 | false, 307 | false, 308 | false 309 | ], 310 | [ 311 | "20190114", 312 | "1", 313 | true, 314 | true, 315 | false 316 | ], 317 | [ 318 | "20190115", 319 | "2", 320 | true, 321 | true, 322 | true 323 | ], 324 | [ 325 | "20190116", 326 | "3", 327 | true, 328 | true, 329 | true 330 | ], 331 | [ 332 | "20190117", 333 | "4", 334 | true, 335 | true, 336 | true 337 | ], 338 | [ 339 | "20190118", 340 | "5", 341 | true, 342 | true, 343 | true 344 | ], 345 | [ 346 | "20190119", 347 | "6", 348 | false, 349 | false, 350 | true 351 | ], 352 | [ 353 | "20190120", 354 | "0", 355 | false, 356 | false, 357 | false 358 | ], 359 | [ 360 | "20190121", 361 | "1", 362 | true, 363 | true, 364 | false 365 | ], 366 | [ 367 | "20190122", 368 | "2", 369 | true, 370 | true, 371 | true 372 | ], 373 | [ 374 | "20190123", 375 | "3", 376 | true, 377 | true, 378 | true 379 | ], 380 | [ 381 | "20190124", 382 | "4", 383 | true, 384 | true, 385 | true 386 | ], 387 | [ 388 | "20190125", 389 | "5", 390 | true, 391 | true, 392 | true 393 | ], 394 | [ 395 | "20190126", 396 | "6", 397 | false, 398 | false, 399 | true 400 | ], 401 | [ 402 | "20190127", 403 | "0", 404 | false, 405 | false, 406 | false 407 | ], 408 | [ 409 | "20190128", 410 | "1", 411 | true, 412 | true, 413 | false 414 | ], 415 | [ 416 | "20190129", 417 | "2", 418 | true, 419 | true, 420 | true 421 | ], 422 | [ 423 | "20190130", 424 | "3", 425 | true, 426 | true, 427 | true 428 | ], 429 | [ 430 | "20190131", 431 | "4", 432 | true, 433 | true, 434 | true 435 | ], 436 | [ 437 | "20190201", 438 | "5", 439 | true, 440 | false, 441 | true 442 | ], 443 | [ 444 | "20190202", 445 | "6", 446 | false, 447 | false, 448 | false 449 | ], 450 | [ 451 | "20190203", 452 | "0", 453 | false, 454 | false, 455 | false 456 | ], 457 | [ 458 | "20190204", 459 | "1", 460 | false, 461 | false, 462 | false 463 | ], 464 | [ 465 | "20190205", 466 | "2", 467 | false, 468 | false, 469 | false 470 | ], 471 | [ 472 | "20190206", 473 | "3", 474 | false, 475 | false, 476 | false 477 | ], 478 | [ 479 | "20190207", 480 | "4", 481 | false, 482 | false, 483 | false 484 | ], 485 | [ 486 | "20190208", 487 | "5", 488 | false, 489 | false, 490 | false 491 | ], 492 | [ 493 | "20190209", 494 | "6", 495 | false, 496 | false, 497 | false 498 | ], 499 | [ 500 | "20190210", 501 | "0", 502 | false, 503 | false, 504 | false 505 | ], 506 | [ 507 | "20190211", 508 | "1", 509 | true, 510 | true, 511 | false 512 | ], 513 | [ 514 | "20190212", 515 | "2", 516 | true, 517 | true, 518 | true 519 | ], 520 | [ 521 | "20190213", 522 | "3", 523 | true, 524 | true, 525 | true 526 | ], 527 | [ 528 | "20190214", 529 | "4", 530 | true, 531 | true, 532 | true 533 | ], 534 | [ 535 | "20190215", 536 | "5", 537 | true, 538 | true, 539 | true 540 | ], 541 | [ 542 | "20190216", 543 | "6", 544 | false, 545 | false, 546 | true 547 | ], 548 | [ 549 | "20190217", 550 | "0", 551 | false, 552 | false, 553 | false 554 | ], 555 | [ 556 | "20190218", 557 | "1", 558 | true, 559 | true, 560 | false 561 | ], 562 | [ 563 | "20190219", 564 | "2", 565 | true, 566 | true, 567 | true 568 | ], 569 | [ 570 | "20190220", 571 | "3", 572 | true, 573 | true, 574 | true 575 | ], 576 | [ 577 | "20190221", 578 | "4", 579 | true, 580 | true, 581 | true 582 | ], 583 | [ 584 | "20190222", 585 | "5", 586 | true, 587 | true, 588 | true 589 | ], 590 | [ 591 | "20190223", 592 | "6", 593 | false, 594 | false, 595 | true 596 | ], 597 | [ 598 | "20190224", 599 | "0", 600 | false, 601 | false, 602 | false 603 | ], 604 | [ 605 | "20190225", 606 | "1", 607 | true, 608 | true, 609 | false 610 | ], 611 | [ 612 | "20190226", 613 | "2", 614 | true, 615 | true, 616 | true 617 | ], 618 | [ 619 | "20190227", 620 | "3", 621 | true, 622 | true, 623 | true 624 | ], 625 | [ 626 | "20190228", 627 | "4", 628 | true, 629 | true, 630 | true 631 | ], 632 | [ 633 | "20190301", 634 | "5", 635 | true, 636 | true, 637 | true 638 | ], 639 | [ 640 | "20190302", 641 | "6", 642 | false, 643 | false, 644 | true 645 | ], 646 | [ 647 | "20190303", 648 | "0", 649 | false, 650 | false, 651 | false 652 | ], 653 | [ 654 | "20190304", 655 | "1", 656 | true, 657 | true, 658 | false 659 | ], 660 | [ 661 | "20190305", 662 | "2", 663 | true, 664 | true, 665 | true 666 | ], 667 | [ 668 | "20190306", 669 | "3", 670 | true, 671 | true, 672 | true 673 | ], 674 | [ 675 | "20190307", 676 | "4", 677 | true, 678 | true, 679 | true 680 | ], 681 | [ 682 | "20190308", 683 | "5", 684 | true, 685 | true, 686 | true 687 | ], 688 | [ 689 | "20190309", 690 | "6", 691 | false, 692 | false, 693 | true 694 | ], 695 | [ 696 | "20190310", 697 | "0", 698 | false, 699 | false, 700 | false 701 | ], 702 | [ 703 | "20190311", 704 | "1", 705 | true, 706 | true, 707 | false 708 | ], 709 | [ 710 | "20190312", 711 | "2", 712 | true, 713 | true, 714 | true 715 | ], 716 | [ 717 | "20190313", 718 | "3", 719 | true, 720 | true, 721 | true 722 | ], 723 | [ 724 | "20190314", 725 | "4", 726 | true, 727 | true, 728 | true 729 | ], 730 | [ 731 | "20190315", 732 | "5", 733 | true, 734 | true, 735 | true 736 | ], 737 | [ 738 | "20190316", 739 | "6", 740 | false, 741 | false, 742 | true 743 | ], 744 | [ 745 | "20190317", 746 | "0", 747 | false, 748 | false, 749 | false 750 | ], 751 | [ 752 | "20190318", 753 | "1", 754 | true, 755 | true, 756 | false 757 | ], 758 | [ 759 | "20190319", 760 | "2", 761 | true, 762 | true, 763 | true 764 | ], 765 | [ 766 | "20190320", 767 | "3", 768 | true, 769 | true, 770 | true 771 | ], 772 | [ 773 | "20190321", 774 | "4", 775 | true, 776 | true, 777 | true 778 | ], 779 | [ 780 | "20190322", 781 | "5", 782 | true, 783 | true, 784 | true 785 | ], 786 | [ 787 | "20190323", 788 | "6", 789 | false, 790 | false, 791 | true 792 | ], 793 | [ 794 | "20190324", 795 | "0", 796 | false, 797 | false, 798 | false 799 | ], 800 | [ 801 | "20190325", 802 | "1", 803 | true, 804 | true, 805 | false 806 | ], 807 | [ 808 | "20190326", 809 | "2", 810 | true, 811 | true, 812 | true 813 | ], 814 | [ 815 | "20190327", 816 | "3", 817 | true, 818 | true, 819 | true 820 | ], 821 | [ 822 | "20190328", 823 | "4", 824 | true, 825 | true, 826 | true 827 | ], 828 | [ 829 | "20190329", 830 | "5", 831 | true, 832 | true, 833 | true 834 | ], 835 | [ 836 | "20190330", 837 | "6", 838 | false, 839 | false, 840 | true 841 | ], 842 | [ 843 | "20190331", 844 | "0", 845 | false, 846 | false, 847 | false 848 | ], 849 | [ 850 | "20190401", 851 | "1", 852 | true, 853 | true, 854 | false 855 | ], 856 | [ 857 | "20190402", 858 | "2", 859 | true, 860 | true, 861 | true 862 | ], 863 | [ 864 | "20190403", 865 | "3", 866 | true, 867 | true, 868 | true 869 | ], 870 | [ 871 | "20190404", 872 | "4", 873 | true, 874 | false, 875 | true 876 | ], 877 | [ 878 | "20190405", 879 | "5", 880 | false, 881 | false, 882 | false 883 | ], 884 | [ 885 | "20190406", 886 | "6", 887 | false, 888 | false, 889 | false 890 | ], 891 | [ 892 | "20190407", 893 | "0", 894 | false, 895 | false, 896 | false 897 | ], 898 | [ 899 | "20190408", 900 | "1", 901 | true, 902 | true, 903 | false 904 | ], 905 | [ 906 | "20190409", 907 | "2", 908 | true, 909 | true, 910 | true 911 | ], 912 | [ 913 | "20190410", 914 | "3", 915 | true, 916 | true, 917 | true 918 | ], 919 | [ 920 | "20190411", 921 | "4", 922 | true, 923 | true, 924 | true 925 | ], 926 | [ 927 | "20190412", 928 | "5", 929 | true, 930 | true, 931 | true 932 | ], 933 | [ 934 | "20190413", 935 | "6", 936 | false, 937 | false, 938 | true 939 | ], 940 | [ 941 | "20190414", 942 | "0", 943 | false, 944 | false, 945 | false 946 | ], 947 | [ 948 | "20190415", 949 | "1", 950 | true, 951 | true, 952 | false 953 | ], 954 | [ 955 | "20190416", 956 | "2", 957 | true, 958 | true, 959 | true 960 | ], 961 | [ 962 | "20190417", 963 | "3", 964 | true, 965 | true, 966 | true 967 | ], 968 | [ 969 | "20190418", 970 | "4", 971 | true, 972 | true, 973 | true 974 | ], 975 | [ 976 | "20190419", 977 | "5", 978 | true, 979 | true, 980 | true 981 | ], 982 | [ 983 | "20190420", 984 | "6", 985 | false, 986 | false, 987 | true 988 | ], 989 | [ 990 | "20190421", 991 | "0", 992 | false, 993 | false, 994 | false 995 | ], 996 | [ 997 | "20190422", 998 | "1", 999 | true, 1000 | true, 1001 | false 1002 | ], 1003 | [ 1004 | "20190423", 1005 | "2", 1006 | true, 1007 | true, 1008 | true 1009 | ], 1010 | [ 1011 | "20190424", 1012 | "3", 1013 | true, 1014 | true, 1015 | true 1016 | ], 1017 | [ 1018 | "20190425", 1019 | "4", 1020 | true, 1021 | true, 1022 | true 1023 | ], 1024 | [ 1025 | "20190426", 1026 | "5", 1027 | true, 1028 | true, 1029 | true 1030 | ], 1031 | [ 1032 | "20190427", 1033 | "6", 1034 | false, 1035 | false, 1036 | true 1037 | ], 1038 | [ 1039 | "20190428", 1040 | "0", 1041 | false, 1042 | false, 1043 | false 1044 | ], 1045 | [ 1046 | "20190429", 1047 | "1", 1048 | true, 1049 | true, 1050 | false 1051 | ], 1052 | [ 1053 | "20190430", 1054 | "2", 1055 | true, 1056 | false, 1057 | true 1058 | ], 1059 | [ 1060 | "20190501", 1061 | "3", 1062 | false, 1063 | false, 1064 | false 1065 | ], 1066 | [ 1067 | "20190502", 1068 | "4", 1069 | true, 1070 | true, 1071 | false 1072 | ], 1073 | [ 1074 | "20190503", 1075 | "5", 1076 | true, 1077 | true, 1078 | true 1079 | ], 1080 | [ 1081 | "20190504", 1082 | "6", 1083 | false, 1084 | false, 1085 | true 1086 | ], 1087 | [ 1088 | "20190505", 1089 | "0", 1090 | false, 1091 | false, 1092 | false 1093 | ], 1094 | [ 1095 | "20190506", 1096 | "1", 1097 | true, 1098 | true, 1099 | false 1100 | ], 1101 | [ 1102 | "20190507", 1103 | "2", 1104 | true, 1105 | true, 1106 | true 1107 | ], 1108 | [ 1109 | "20190508", 1110 | "3", 1111 | true, 1112 | true, 1113 | true 1114 | ], 1115 | [ 1116 | "20190509", 1117 | "4", 1118 | true, 1119 | true, 1120 | true 1121 | ], 1122 | [ 1123 | "20190510", 1124 | "5", 1125 | true, 1126 | true, 1127 | true 1128 | ], 1129 | [ 1130 | "20190511", 1131 | "6", 1132 | false, 1133 | false, 1134 | true 1135 | ], 1136 | [ 1137 | "20190512", 1138 | "0", 1139 | false, 1140 | false, 1141 | false 1142 | ], 1143 | [ 1144 | "20190513", 1145 | "1", 1146 | true, 1147 | true, 1148 | false 1149 | ], 1150 | [ 1151 | "20190514", 1152 | "2", 1153 | true, 1154 | true, 1155 | true 1156 | ], 1157 | [ 1158 | "20190515", 1159 | "3", 1160 | true, 1161 | true, 1162 | true 1163 | ], 1164 | [ 1165 | "20190516", 1166 | "4", 1167 | true, 1168 | true, 1169 | true 1170 | ], 1171 | [ 1172 | "20190517", 1173 | "5", 1174 | true, 1175 | true, 1176 | true 1177 | ], 1178 | [ 1179 | "20190518", 1180 | "6", 1181 | false, 1182 | false, 1183 | true 1184 | ], 1185 | [ 1186 | "20190519", 1187 | "0", 1188 | false, 1189 | false, 1190 | false 1191 | ], 1192 | [ 1193 | "20190520", 1194 | "1", 1195 | true, 1196 | true, 1197 | false 1198 | ], 1199 | [ 1200 | "20190521", 1201 | "2", 1202 | true, 1203 | true, 1204 | true 1205 | ], 1206 | [ 1207 | "20190522", 1208 | "3", 1209 | true, 1210 | true, 1211 | true 1212 | ], 1213 | [ 1214 | "20190523", 1215 | "4", 1216 | true, 1217 | true, 1218 | true 1219 | ], 1220 | [ 1221 | "20190524", 1222 | "5", 1223 | true, 1224 | true, 1225 | true 1226 | ], 1227 | [ 1228 | "20190525", 1229 | "6", 1230 | false, 1231 | false, 1232 | true 1233 | ], 1234 | [ 1235 | "20190526", 1236 | "0", 1237 | false, 1238 | false, 1239 | false 1240 | ], 1241 | [ 1242 | "20190527", 1243 | "1", 1244 | true, 1245 | true, 1246 | false 1247 | ], 1248 | [ 1249 | "20190528", 1250 | "2", 1251 | true, 1252 | true, 1253 | true 1254 | ], 1255 | [ 1256 | "20190529", 1257 | "3", 1258 | true, 1259 | true, 1260 | true 1261 | ], 1262 | [ 1263 | "20190530", 1264 | "4", 1265 | true, 1266 | true, 1267 | true 1268 | ], 1269 | [ 1270 | "20190531", 1271 | "5", 1272 | true, 1273 | true, 1274 | true 1275 | ], 1276 | [ 1277 | "20190601", 1278 | "6", 1279 | false, 1280 | false, 1281 | true 1282 | ], 1283 | [ 1284 | "20190602", 1285 | "0", 1286 | false, 1287 | false, 1288 | false 1289 | ], 1290 | [ 1291 | "20190603", 1292 | "1", 1293 | true, 1294 | true, 1295 | false 1296 | ], 1297 | [ 1298 | "20190604", 1299 | "2", 1300 | true, 1301 | true, 1302 | true 1303 | ], 1304 | [ 1305 | "20190605", 1306 | "3", 1307 | true, 1308 | true, 1309 | true 1310 | ], 1311 | [ 1312 | "20190606", 1313 | "4", 1314 | true, 1315 | false, 1316 | true 1317 | ], 1318 | [ 1319 | "20190607", 1320 | "5", 1321 | false, 1322 | false, 1323 | false 1324 | ], 1325 | [ 1326 | "20190608", 1327 | "6", 1328 | false, 1329 | false, 1330 | false 1331 | ], 1332 | [ 1333 | "20190609", 1334 | "0", 1335 | false, 1336 | false, 1337 | false 1338 | ], 1339 | [ 1340 | "20190610", 1341 | "1", 1342 | true, 1343 | true, 1344 | false 1345 | ], 1346 | [ 1347 | "20190611", 1348 | "2", 1349 | true, 1350 | true, 1351 | true 1352 | ], 1353 | [ 1354 | "20190612", 1355 | "3", 1356 | true, 1357 | true, 1358 | true 1359 | ], 1360 | [ 1361 | "20190613", 1362 | "4", 1363 | true, 1364 | true, 1365 | true 1366 | ], 1367 | [ 1368 | "20190614", 1369 | "5", 1370 | true, 1371 | true, 1372 | true 1373 | ], 1374 | [ 1375 | "20190615", 1376 | "6", 1377 | false, 1378 | false, 1379 | true 1380 | ], 1381 | [ 1382 | "20190616", 1383 | "0", 1384 | false, 1385 | false, 1386 | false 1387 | ], 1388 | [ 1389 | "20190617", 1390 | "1", 1391 | true, 1392 | true, 1393 | false 1394 | ], 1395 | [ 1396 | "20190618", 1397 | "2", 1398 | true, 1399 | true, 1400 | true 1401 | ], 1402 | [ 1403 | "20190619", 1404 | "3", 1405 | true, 1406 | true, 1407 | true 1408 | ], 1409 | [ 1410 | "20190620", 1411 | "4", 1412 | true, 1413 | true, 1414 | true 1415 | ], 1416 | [ 1417 | "20190621", 1418 | "5", 1419 | true, 1420 | true, 1421 | true 1422 | ], 1423 | [ 1424 | "20190622", 1425 | "6", 1426 | false, 1427 | false, 1428 | true 1429 | ], 1430 | [ 1431 | "20190623", 1432 | "0", 1433 | false, 1434 | false, 1435 | false 1436 | ], 1437 | [ 1438 | "20190624", 1439 | "1", 1440 | true, 1441 | true, 1442 | false 1443 | ], 1444 | [ 1445 | "20190625", 1446 | "2", 1447 | true, 1448 | true, 1449 | true 1450 | ], 1451 | [ 1452 | "20190626", 1453 | "3", 1454 | true, 1455 | true, 1456 | true 1457 | ], 1458 | [ 1459 | "20190627", 1460 | "4", 1461 | true, 1462 | true, 1463 | true 1464 | ], 1465 | [ 1466 | "20190628", 1467 | "5", 1468 | true, 1469 | true, 1470 | true 1471 | ], 1472 | [ 1473 | "20190629", 1474 | "6", 1475 | false, 1476 | false, 1477 | true 1478 | ], 1479 | [ 1480 | "20190630", 1481 | "0", 1482 | false, 1483 | false, 1484 | false 1485 | ], 1486 | [ 1487 | "20190701", 1488 | "1", 1489 | true, 1490 | true, 1491 | false 1492 | ], 1493 | [ 1494 | "20190702", 1495 | "2", 1496 | true, 1497 | true, 1498 | true 1499 | ], 1500 | [ 1501 | "20190703", 1502 | "3", 1503 | true, 1504 | true, 1505 | true 1506 | ], 1507 | [ 1508 | "20190704", 1509 | "4", 1510 | true, 1511 | true, 1512 | true 1513 | ], 1514 | [ 1515 | "20190705", 1516 | "5", 1517 | true, 1518 | true, 1519 | true 1520 | ], 1521 | [ 1522 | "20190706", 1523 | "6", 1524 | false, 1525 | false, 1526 | true 1527 | ], 1528 | [ 1529 | "20190707", 1530 | "0", 1531 | false, 1532 | false, 1533 | false 1534 | ], 1535 | [ 1536 | "20190708", 1537 | "1", 1538 | true, 1539 | true, 1540 | false 1541 | ], 1542 | [ 1543 | "20190709", 1544 | "2", 1545 | true, 1546 | true, 1547 | true 1548 | ], 1549 | [ 1550 | "20190710", 1551 | "3", 1552 | true, 1553 | true, 1554 | true 1555 | ], 1556 | [ 1557 | "20190711", 1558 | "4", 1559 | true, 1560 | true, 1561 | true 1562 | ], 1563 | [ 1564 | "20190712", 1565 | "5", 1566 | true, 1567 | true, 1568 | true 1569 | ], 1570 | [ 1571 | "20190713", 1572 | "6", 1573 | false, 1574 | false, 1575 | true 1576 | ], 1577 | [ 1578 | "20190714", 1579 | "0", 1580 | false, 1581 | false, 1582 | false 1583 | ], 1584 | [ 1585 | "20190715", 1586 | "1", 1587 | true, 1588 | true, 1589 | false 1590 | ], 1591 | [ 1592 | "20190716", 1593 | "2", 1594 | true, 1595 | true, 1596 | true 1597 | ], 1598 | [ 1599 | "20190717", 1600 | "3", 1601 | true, 1602 | true, 1603 | true 1604 | ], 1605 | [ 1606 | "20190718", 1607 | "4", 1608 | true, 1609 | true, 1610 | true 1611 | ], 1612 | [ 1613 | "20190719", 1614 | "5", 1615 | true, 1616 | true, 1617 | true 1618 | ], 1619 | [ 1620 | "20190720", 1621 | "6", 1622 | false, 1623 | false, 1624 | true 1625 | ], 1626 | [ 1627 | "20190721", 1628 | "0", 1629 | false, 1630 | false, 1631 | false 1632 | ], 1633 | [ 1634 | "20190722", 1635 | "1", 1636 | true, 1637 | true, 1638 | false 1639 | ], 1640 | [ 1641 | "20190723", 1642 | "2", 1643 | true, 1644 | true, 1645 | true 1646 | ], 1647 | [ 1648 | "20190724", 1649 | "3", 1650 | true, 1651 | true, 1652 | true 1653 | ], 1654 | [ 1655 | "20190725", 1656 | "4", 1657 | true, 1658 | true, 1659 | true 1660 | ], 1661 | [ 1662 | "20190726", 1663 | "5", 1664 | true, 1665 | true, 1666 | true 1667 | ], 1668 | [ 1669 | "20190727", 1670 | "6", 1671 | false, 1672 | false, 1673 | true 1674 | ], 1675 | [ 1676 | "20190728", 1677 | "0", 1678 | false, 1679 | false, 1680 | false 1681 | ], 1682 | [ 1683 | "20190729", 1684 | "1", 1685 | true, 1686 | true, 1687 | false 1688 | ], 1689 | [ 1690 | "20190730", 1691 | "2", 1692 | true, 1693 | true, 1694 | true 1695 | ], 1696 | [ 1697 | "20190731", 1698 | "3", 1699 | true, 1700 | true, 1701 | true 1702 | ], 1703 | [ 1704 | "20190801", 1705 | "4", 1706 | true, 1707 | true, 1708 | true 1709 | ], 1710 | [ 1711 | "20190802", 1712 | "5", 1713 | true, 1714 | true, 1715 | true 1716 | ], 1717 | [ 1718 | "20190803", 1719 | "6", 1720 | false, 1721 | false, 1722 | true 1723 | ], 1724 | [ 1725 | "20190804", 1726 | "0", 1727 | false, 1728 | false, 1729 | false 1730 | ], 1731 | [ 1732 | "20190805", 1733 | "1", 1734 | true, 1735 | true, 1736 | false 1737 | ], 1738 | [ 1739 | "20190806", 1740 | "2", 1741 | true, 1742 | true, 1743 | true 1744 | ], 1745 | [ 1746 | "20190807", 1747 | "3", 1748 | true, 1749 | true, 1750 | true 1751 | ], 1752 | [ 1753 | "20190808", 1754 | "4", 1755 | true, 1756 | true, 1757 | true 1758 | ], 1759 | [ 1760 | "20190809", 1761 | "5", 1762 | true, 1763 | true, 1764 | true 1765 | ], 1766 | [ 1767 | "20190810", 1768 | "6", 1769 | false, 1770 | false, 1771 | true 1772 | ], 1773 | [ 1774 | "20190811", 1775 | "0", 1776 | false, 1777 | false, 1778 | false 1779 | ], 1780 | [ 1781 | "20190812", 1782 | "1", 1783 | true, 1784 | true, 1785 | false 1786 | ], 1787 | [ 1788 | "20190813", 1789 | "2", 1790 | true, 1791 | true, 1792 | true 1793 | ], 1794 | [ 1795 | "20190814", 1796 | "3", 1797 | true, 1798 | true, 1799 | true 1800 | ], 1801 | [ 1802 | "20190815", 1803 | "4", 1804 | true, 1805 | true, 1806 | true 1807 | ], 1808 | [ 1809 | "20190816", 1810 | "5", 1811 | true, 1812 | true, 1813 | true 1814 | ], 1815 | [ 1816 | "20190817", 1817 | "6", 1818 | false, 1819 | false, 1820 | true 1821 | ], 1822 | [ 1823 | "20190818", 1824 | "0", 1825 | false, 1826 | false, 1827 | false 1828 | ], 1829 | [ 1830 | "20190819", 1831 | "1", 1832 | true, 1833 | true, 1834 | false 1835 | ], 1836 | [ 1837 | "20190820", 1838 | "2", 1839 | true, 1840 | true, 1841 | true 1842 | ], 1843 | [ 1844 | "20190821", 1845 | "3", 1846 | true, 1847 | true, 1848 | true 1849 | ], 1850 | [ 1851 | "20190822", 1852 | "4", 1853 | true, 1854 | true, 1855 | true 1856 | ], 1857 | [ 1858 | "20190823", 1859 | "5", 1860 | true, 1861 | true, 1862 | true 1863 | ], 1864 | [ 1865 | "20190824", 1866 | "6", 1867 | false, 1868 | false, 1869 | true 1870 | ], 1871 | [ 1872 | "20190825", 1873 | "0", 1874 | false, 1875 | false, 1876 | false 1877 | ], 1878 | [ 1879 | "20190826", 1880 | "1", 1881 | true, 1882 | true, 1883 | false 1884 | ], 1885 | [ 1886 | "20190827", 1887 | "2", 1888 | true, 1889 | true, 1890 | true 1891 | ], 1892 | [ 1893 | "20190828", 1894 | "3", 1895 | true, 1896 | true, 1897 | true 1898 | ], 1899 | [ 1900 | "20190829", 1901 | "4", 1902 | true, 1903 | true, 1904 | true 1905 | ], 1906 | [ 1907 | "20190830", 1908 | "5", 1909 | true, 1910 | true, 1911 | true 1912 | ], 1913 | [ 1914 | "20190831", 1915 | "6", 1916 | false, 1917 | false, 1918 | true 1919 | ], 1920 | [ 1921 | "20190901", 1922 | "0", 1923 | false, 1924 | false, 1925 | false 1926 | ], 1927 | [ 1928 | "20190902", 1929 | "1", 1930 | true, 1931 | true, 1932 | false 1933 | ], 1934 | [ 1935 | "20190903", 1936 | "2", 1937 | true, 1938 | true, 1939 | true 1940 | ], 1941 | [ 1942 | "20190904", 1943 | "3", 1944 | true, 1945 | true, 1946 | true 1947 | ], 1948 | [ 1949 | "20190905", 1950 | "4", 1951 | true, 1952 | true, 1953 | true 1954 | ], 1955 | [ 1956 | "20190906", 1957 | "5", 1958 | true, 1959 | true, 1960 | true 1961 | ], 1962 | [ 1963 | "20190907", 1964 | "6", 1965 | false, 1966 | false, 1967 | true 1968 | ], 1969 | [ 1970 | "20190908", 1971 | "0", 1972 | false, 1973 | false, 1974 | false 1975 | ], 1976 | [ 1977 | "20190909", 1978 | "1", 1979 | true, 1980 | true, 1981 | false 1982 | ], 1983 | [ 1984 | "20190910", 1985 | "2", 1986 | true, 1987 | true, 1988 | true 1989 | ], 1990 | [ 1991 | "20190911", 1992 | "3", 1993 | true, 1994 | true, 1995 | true 1996 | ], 1997 | [ 1998 | "20190912", 1999 | "4", 2000 | true, 2001 | false, 2002 | true 2003 | ], 2004 | [ 2005 | "20190913", 2006 | "5", 2007 | false, 2008 | false, 2009 | false 2010 | ], 2011 | [ 2012 | "20190914", 2013 | "6", 2014 | false, 2015 | false, 2016 | false 2017 | ], 2018 | [ 2019 | "20190915", 2020 | "0", 2021 | false, 2022 | false, 2023 | false 2024 | ], 2025 | [ 2026 | "20190916", 2027 | "1", 2028 | true, 2029 | true, 2030 | false 2031 | ], 2032 | [ 2033 | "20190917", 2034 | "2", 2035 | true, 2036 | true, 2037 | true 2038 | ], 2039 | [ 2040 | "20190918", 2041 | "3", 2042 | true, 2043 | true, 2044 | true 2045 | ], 2046 | [ 2047 | "20190919", 2048 | "4", 2049 | true, 2050 | true, 2051 | true 2052 | ], 2053 | [ 2054 | "20190920", 2055 | "5", 2056 | true, 2057 | true, 2058 | true 2059 | ], 2060 | [ 2061 | "20190921", 2062 | "6", 2063 | false, 2064 | false, 2065 | true 2066 | ], 2067 | [ 2068 | "20190922", 2069 | "0", 2070 | false, 2071 | false, 2072 | false 2073 | ], 2074 | [ 2075 | "20190923", 2076 | "1", 2077 | true, 2078 | true, 2079 | false 2080 | ], 2081 | [ 2082 | "20190924", 2083 | "2", 2084 | true, 2085 | true, 2086 | true 2087 | ], 2088 | [ 2089 | "20190925", 2090 | "3", 2091 | true, 2092 | true, 2093 | true 2094 | ], 2095 | [ 2096 | "20190926", 2097 | "4", 2098 | true, 2099 | true, 2100 | true 2101 | ], 2102 | [ 2103 | "20190927", 2104 | "5", 2105 | true, 2106 | true, 2107 | true 2108 | ], 2109 | [ 2110 | "20190928", 2111 | "6", 2112 | false, 2113 | false, 2114 | true 2115 | ], 2116 | [ 2117 | "20190929", 2118 | "0", 2119 | false, 2120 | false, 2121 | false 2122 | ], 2123 | [ 2124 | "20190930", 2125 | "1", 2126 | true, 2127 | false, 2128 | false 2129 | ], 2130 | [ 2131 | "20191001", 2132 | "2", 2133 | false, 2134 | false, 2135 | false 2136 | ], 2137 | [ 2138 | "20191002", 2139 | "3", 2140 | false, 2141 | false, 2142 | false 2143 | ], 2144 | [ 2145 | "20191003", 2146 | "4", 2147 | false, 2148 | false, 2149 | false 2150 | ], 2151 | [ 2152 | "20191004", 2153 | "5", 2154 | false, 2155 | false, 2156 | false 2157 | ], 2158 | [ 2159 | "20191005", 2160 | "6", 2161 | false, 2162 | false, 2163 | false 2164 | ], 2165 | [ 2166 | "20191006", 2167 | "0", 2168 | false, 2169 | false, 2170 | false 2171 | ], 2172 | [ 2173 | "20191007", 2174 | "1", 2175 | false, 2176 | false, 2177 | false 2178 | ], 2179 | [ 2180 | "20191008", 2181 | "2", 2182 | true, 2183 | true, 2184 | false 2185 | ], 2186 | [ 2187 | "20191009", 2188 | "3", 2189 | true, 2190 | true, 2191 | true 2192 | ], 2193 | [ 2194 | "20191010", 2195 | "4", 2196 | true, 2197 | true, 2198 | true 2199 | ], 2200 | [ 2201 | "20191011", 2202 | "5", 2203 | true, 2204 | true, 2205 | true 2206 | ], 2207 | [ 2208 | "20191012", 2209 | "6", 2210 | false, 2211 | false, 2212 | true 2213 | ], 2214 | [ 2215 | "20191013", 2216 | "0", 2217 | false, 2218 | false, 2219 | false 2220 | ], 2221 | [ 2222 | "20191014", 2223 | "1", 2224 | true, 2225 | true, 2226 | false 2227 | ], 2228 | [ 2229 | "20191015", 2230 | "2", 2231 | true, 2232 | true, 2233 | true 2234 | ], 2235 | [ 2236 | "20191016", 2237 | "3", 2238 | true, 2239 | true, 2240 | true 2241 | ], 2242 | [ 2243 | "20191017", 2244 | "4", 2245 | true, 2246 | true, 2247 | true 2248 | ], 2249 | [ 2250 | "20191018", 2251 | "5", 2252 | true, 2253 | true, 2254 | true 2255 | ], 2256 | [ 2257 | "20191019", 2258 | "6", 2259 | false, 2260 | false, 2261 | true 2262 | ], 2263 | [ 2264 | "20191020", 2265 | "0", 2266 | false, 2267 | false, 2268 | false 2269 | ], 2270 | [ 2271 | "20191021", 2272 | "1", 2273 | true, 2274 | true, 2275 | false 2276 | ], 2277 | [ 2278 | "20191022", 2279 | "2", 2280 | true, 2281 | true, 2282 | true 2283 | ], 2284 | [ 2285 | "20191023", 2286 | "3", 2287 | true, 2288 | true, 2289 | true 2290 | ], 2291 | [ 2292 | "20191024", 2293 | "4", 2294 | true, 2295 | true, 2296 | true 2297 | ], 2298 | [ 2299 | "20191025", 2300 | "5", 2301 | true, 2302 | true, 2303 | true 2304 | ], 2305 | [ 2306 | "20191026", 2307 | "6", 2308 | false, 2309 | false, 2310 | true 2311 | ], 2312 | [ 2313 | "20191027", 2314 | "0", 2315 | false, 2316 | false, 2317 | false 2318 | ], 2319 | [ 2320 | "20191028", 2321 | "1", 2322 | true, 2323 | true, 2324 | false 2325 | ], 2326 | [ 2327 | "20191029", 2328 | "2", 2329 | true, 2330 | true, 2331 | true 2332 | ], 2333 | [ 2334 | "20191030", 2335 | "3", 2336 | true, 2337 | true, 2338 | true 2339 | ], 2340 | [ 2341 | "20191031", 2342 | "4", 2343 | true, 2344 | true, 2345 | true 2346 | ], 2347 | [ 2348 | "20191101", 2349 | "5", 2350 | true, 2351 | true, 2352 | true 2353 | ], 2354 | [ 2355 | "20191102", 2356 | "6", 2357 | false, 2358 | false, 2359 | true 2360 | ], 2361 | [ 2362 | "20191103", 2363 | "0", 2364 | false, 2365 | false, 2366 | false 2367 | ], 2368 | [ 2369 | "20191104", 2370 | "1", 2371 | true, 2372 | true, 2373 | false 2374 | ], 2375 | [ 2376 | "20191105", 2377 | "2", 2378 | true, 2379 | true, 2380 | true 2381 | ], 2382 | [ 2383 | "20191106", 2384 | "3", 2385 | true, 2386 | true, 2387 | true 2388 | ], 2389 | [ 2390 | "20191107", 2391 | "4", 2392 | true, 2393 | true, 2394 | true 2395 | ], 2396 | [ 2397 | "20191108", 2398 | "5", 2399 | true, 2400 | true, 2401 | true 2402 | ], 2403 | [ 2404 | "20191109", 2405 | "6", 2406 | false, 2407 | false, 2408 | true 2409 | ], 2410 | [ 2411 | "20191110", 2412 | "0", 2413 | false, 2414 | false, 2415 | false 2416 | ], 2417 | [ 2418 | "20191111", 2419 | "1", 2420 | true, 2421 | true, 2422 | false 2423 | ], 2424 | [ 2425 | "20191112", 2426 | "2", 2427 | true, 2428 | true, 2429 | true 2430 | ], 2431 | [ 2432 | "20191113", 2433 | "3", 2434 | true, 2435 | true, 2436 | true 2437 | ], 2438 | [ 2439 | "20191114", 2440 | "4", 2441 | true, 2442 | true, 2443 | true 2444 | ], 2445 | [ 2446 | "20191115", 2447 | "5", 2448 | true, 2449 | true, 2450 | true 2451 | ], 2452 | [ 2453 | "20191116", 2454 | "6", 2455 | false, 2456 | false, 2457 | true 2458 | ], 2459 | [ 2460 | "20191117", 2461 | "0", 2462 | false, 2463 | false, 2464 | false 2465 | ], 2466 | [ 2467 | "20191118", 2468 | "1", 2469 | true, 2470 | true, 2471 | false 2472 | ], 2473 | [ 2474 | "20191119", 2475 | "2", 2476 | true, 2477 | true, 2478 | true 2479 | ], 2480 | [ 2481 | "20191120", 2482 | "3", 2483 | true, 2484 | true, 2485 | true 2486 | ], 2487 | [ 2488 | "20191121", 2489 | "4", 2490 | true, 2491 | true, 2492 | true 2493 | ], 2494 | [ 2495 | "20191122", 2496 | "5", 2497 | true, 2498 | true, 2499 | true 2500 | ], 2501 | [ 2502 | "20191123", 2503 | "6", 2504 | false, 2505 | false, 2506 | true 2507 | ], 2508 | [ 2509 | "20191124", 2510 | "0", 2511 | false, 2512 | false, 2513 | false 2514 | ], 2515 | [ 2516 | "20191125", 2517 | "1", 2518 | true, 2519 | true, 2520 | false 2521 | ], 2522 | [ 2523 | "20191126", 2524 | "2", 2525 | true, 2526 | true, 2527 | true 2528 | ], 2529 | [ 2530 | "20191127", 2531 | "3", 2532 | true, 2533 | true, 2534 | true 2535 | ], 2536 | [ 2537 | "20191128", 2538 | "4", 2539 | true, 2540 | true, 2541 | true 2542 | ], 2543 | [ 2544 | "20191129", 2545 | "5", 2546 | true, 2547 | true, 2548 | true 2549 | ], 2550 | [ 2551 | "20191130", 2552 | "6", 2553 | false, 2554 | false, 2555 | true 2556 | ], 2557 | [ 2558 | "20191201", 2559 | "0", 2560 | false, 2561 | false, 2562 | false 2563 | ], 2564 | [ 2565 | "20191202", 2566 | "1", 2567 | true, 2568 | true, 2569 | false 2570 | ], 2571 | [ 2572 | "20191203", 2573 | "2", 2574 | true, 2575 | true, 2576 | true 2577 | ], 2578 | [ 2579 | "20191204", 2580 | "3", 2581 | true, 2582 | true, 2583 | true 2584 | ], 2585 | [ 2586 | "20191205", 2587 | "4", 2588 | true, 2589 | true, 2590 | true 2591 | ], 2592 | [ 2593 | "20191206", 2594 | "5", 2595 | true, 2596 | true, 2597 | true 2598 | ], 2599 | [ 2600 | "20191207", 2601 | "6", 2602 | false, 2603 | false, 2604 | true 2605 | ], 2606 | [ 2607 | "20191208", 2608 | "0", 2609 | false, 2610 | false, 2611 | false 2612 | ], 2613 | [ 2614 | "20191209", 2615 | "1", 2616 | true, 2617 | true, 2618 | false 2619 | ], 2620 | [ 2621 | "20191210", 2622 | "2", 2623 | true, 2624 | true, 2625 | true 2626 | ], 2627 | [ 2628 | "20191211", 2629 | "3", 2630 | true, 2631 | true, 2632 | true 2633 | ], 2634 | [ 2635 | "20191212", 2636 | "4", 2637 | true, 2638 | true, 2639 | true 2640 | ], 2641 | [ 2642 | "20191213", 2643 | "5", 2644 | true, 2645 | true, 2646 | true 2647 | ], 2648 | [ 2649 | "20191214", 2650 | "6", 2651 | false, 2652 | false, 2653 | true 2654 | ], 2655 | [ 2656 | "20191215", 2657 | "0", 2658 | false, 2659 | false, 2660 | false 2661 | ], 2662 | [ 2663 | "20191216", 2664 | "1", 2665 | true, 2666 | true, 2667 | false 2668 | ], 2669 | [ 2670 | "20191217", 2671 | "2", 2672 | true, 2673 | true, 2674 | true 2675 | ], 2676 | [ 2677 | "20191218", 2678 | "3", 2679 | true, 2680 | true, 2681 | true 2682 | ], 2683 | [ 2684 | "20191219", 2685 | "4", 2686 | true, 2687 | true, 2688 | true 2689 | ], 2690 | [ 2691 | "20191220", 2692 | "5", 2693 | true, 2694 | true, 2695 | true 2696 | ], 2697 | [ 2698 | "20191221", 2699 | "6", 2700 | false, 2701 | false, 2702 | true 2703 | ], 2704 | [ 2705 | "20191222", 2706 | "0", 2707 | false, 2708 | false, 2709 | false 2710 | ], 2711 | [ 2712 | "20191223", 2713 | "1", 2714 | true, 2715 | true, 2716 | false 2717 | ], 2718 | [ 2719 | "20191224", 2720 | "2", 2721 | true, 2722 | true, 2723 | true 2724 | ], 2725 | [ 2726 | "20191225", 2727 | "3", 2728 | true, 2729 | true, 2730 | true 2731 | ], 2732 | [ 2733 | "20191226", 2734 | "4", 2735 | true, 2736 | true, 2737 | true 2738 | ], 2739 | [ 2740 | "20191227", 2741 | "5", 2742 | true, 2743 | true, 2744 | true 2745 | ], 2746 | [ 2747 | "20191228", 2748 | "6", 2749 | false, 2750 | false, 2751 | true 2752 | ], 2753 | [ 2754 | "20191229", 2755 | "0", 2756 | false, 2757 | false, 2758 | false 2759 | ], 2760 | [ 2761 | "20191230", 2762 | "1", 2763 | true, 2764 | true, 2765 | false 2766 | ], 2767 | [ 2768 | "20191231", 2769 | "2", 2770 | true, 2771 | true, 2772 | true 2773 | ] 2774 | ] -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # VNPY_account_updater 2 | python3版本,ctp接口来自vnpy项目,大部分代码也来自vnpy项目。 3 | 4 | 功能:按交易日列表自动开关软件,盘中记录资金、持仓、委托、未成交信息,保存到本地。后续就可以用werobot和matplotlib实现盘中资金曲线,微信自动回复等功能。 5 | 6 | 注意:需要修改config.json填入账户信息。 7 | --------------------------------------------------------------------------------