初步完成dataRecord的全过程时序
This commit is contained in:
parent
c36a58d5e3
commit
29dd68e883
8
vnpy/trader/app/histDataCollector/__init__.py
Normal file
8
vnpy/trader/app/histDataCollector/__init__.py
Normal file
@ -0,0 +1,8 @@
|
||||
# encoding: UTF-8
|
||||
|
||||
from hdcEngine import HdcEngine
|
||||
|
||||
|
||||
appName = 'HistDataCollector'
|
||||
appDisplayName = u'HistData记录'
|
||||
appEngine = HdcEngine
|
19
vnpy/trader/app/histDataCollector/hdcBase.py
Normal file
19
vnpy/trader/app/histDataCollector/hdcBase.py
Normal file
@ -0,0 +1,19 @@
|
||||
# encoding: UTF-8
|
||||
|
||||
'''
|
||||
本文件中包含的数据格式和CTA模块通用,用户有必要可以自行添加格式。
|
||||
'''
|
||||
|
||||
from __future__ import division
|
||||
|
||||
# 数据库名称
|
||||
SETTING_DB_NAME = 'VnTrader_Setting_Db'
|
||||
TICK_DB_NAME = 'VnTrader_Tick_Db'
|
||||
DAILY_DB_NAME = 'VnTrader_Daily_Db'
|
||||
MINUTE_DB_NAME = 'VnTrader_1Min_Db'
|
||||
|
||||
# 行情记录模块事件
|
||||
EVENT_DATARECORDER_LOG = 'eHistDataCollectorLog' # 行情记录日志更新事件
|
||||
|
||||
# CTA引擎中涉及的数据类定义
|
||||
from vnpy.trader.vtConstant import EMPTY_UNICODE, EMPTY_STRING, EMPTY_FLOAT, EMPTY_INT
|
274
vnpy/trader/app/histDataCollector/hdcEngine.py
Normal file
274
vnpy/trader/app/histDataCollector/hdcEngine.py
Normal file
@ -0,0 +1,274 @@
|
||||
# encoding: UTF-8
|
||||
|
||||
'''
|
||||
本文件中实现了行情数据记录引擎,用于汇总TICK数据,并生成K线插入数据库。
|
||||
|
||||
使用DR_setting.json来配置需要收集的合约,以及主力合约代码。
|
||||
'''
|
||||
|
||||
import json
|
||||
import csv
|
||||
import os
|
||||
import copy
|
||||
import traceback
|
||||
from collections import OrderedDict
|
||||
from datetime import datetime, timedelta
|
||||
from Queue import Queue, Empty
|
||||
from threading import Thread
|
||||
from pymongo.errors import DuplicateKeyError
|
||||
|
||||
from vnpy.event import Event
|
||||
from vnpy.trader.vtEvent import *
|
||||
from vnpy.trader.vtFunction import todayDate, getJsonPath
|
||||
from vnpy.trader.vtObject import VtSubscribeReq, VtLogData, VtBarData, VtTickData
|
||||
from vnpy.trader.app.ctaStrategy.ctaTemplate import BarGenerator
|
||||
|
||||
from .hdcBase import *
|
||||
from .language import text
|
||||
|
||||
|
||||
########################################################################
|
||||
class HdcEngine(object):
|
||||
"""数据记录引擎"""
|
||||
|
||||
settingFileName = 'HD_setting.json'
|
||||
settingFilePath = getJsonPath(settingFileName, __file__)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def __init__(self, mainEngine, eventEngine):
|
||||
"""Constructor"""
|
||||
self.mainEngine = mainEngine
|
||||
self.eventEngine = eventEngine
|
||||
|
||||
# 当前日期
|
||||
self.today = todayDate()
|
||||
|
||||
# 主力合约代码映射字典,key为具体的合约代码(如IF1604),value为主力合约代码(如IF0000)
|
||||
self.activeSymbolDict = {}
|
||||
|
||||
# Tick对象字典
|
||||
self.tickSymbolSet = set()
|
||||
|
||||
# K线合成器字典
|
||||
self.bgDict = {}
|
||||
|
||||
# 配置字典
|
||||
self.settingDict = OrderedDict()
|
||||
|
||||
# 负责执行数据库插入的单独线程相关
|
||||
self.active = False # 工作状态
|
||||
self.queue = Queue() # 队列
|
||||
self.thread = Thread(target=self.run) # 线程
|
||||
|
||||
# 载入设置,订阅行情
|
||||
self.loadSetting()
|
||||
|
||||
# 启动数据插入线程
|
||||
self.start()
|
||||
|
||||
# 注册事件监听
|
||||
self.registerEvent()
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def loadSetting(self):
|
||||
"""加载配置"""
|
||||
with open(self.settingFilePath) as f:
|
||||
drSetting = json.load(f)
|
||||
|
||||
# 如果working设为False则不启动行情记录功能
|
||||
working = drSetting['working']
|
||||
if not working:
|
||||
return
|
||||
|
||||
# Tick记录配置
|
||||
if 'tick' in drSetting:
|
||||
l = drSetting['tick']
|
||||
|
||||
for setting in l:
|
||||
symbol = setting[0]
|
||||
gateway = setting[1]
|
||||
vtSymbol = symbol
|
||||
|
||||
req = VtSubscribeReq()
|
||||
req.symbol = setting[0]
|
||||
|
||||
# 针对LTS和IB接口,订阅行情需要交易所代码
|
||||
if len(setting)>=3:
|
||||
req.exchange = setting[2]
|
||||
vtSymbol = '.'.join([symbol, req.exchange])
|
||||
|
||||
# 针对IB接口,订阅行情需要货币和产品类型
|
||||
if len(setting)>=5:
|
||||
req.currency = setting[3]
|
||||
req.productClass = setting[4]
|
||||
|
||||
self.mainEngine.subscribe(req, gateway)
|
||||
|
||||
#tick = VtTickData() # 该tick实例可以用于缓存部分数据(目前未使用)
|
||||
#self.tickDict[vtSymbol] = tick
|
||||
self.tickSymbolSet.add(vtSymbol)
|
||||
|
||||
# 保存到配置字典中
|
||||
if vtSymbol not in self.settingDict:
|
||||
d = {
|
||||
'symbol': symbol,
|
||||
'gateway': gateway,
|
||||
'tick': True
|
||||
}
|
||||
self.settingDict[vtSymbol] = d
|
||||
else:
|
||||
d = self.settingDict[vtSymbol]
|
||||
d['tick'] = True
|
||||
|
||||
# 分钟线记录配置
|
||||
if 'bar' in drSetting:
|
||||
l = drSetting['bar']
|
||||
|
||||
for setting in l:
|
||||
symbol = setting[0]
|
||||
gateway = setting[1]
|
||||
vtSymbol = symbol
|
||||
|
||||
req = VtSubscribeReq()
|
||||
req.symbol = symbol
|
||||
|
||||
if len(setting)>=3:
|
||||
req.exchange = setting[2]
|
||||
vtSymbol = '.'.join([symbol, req.exchange])
|
||||
|
||||
if len(setting)>=5:
|
||||
req.currency = setting[3]
|
||||
req.productClass = setting[4]
|
||||
|
||||
self.mainEngine.subscribe(req, gateway)
|
||||
|
||||
# 保存到配置字典中
|
||||
if vtSymbol not in self.settingDict:
|
||||
d = {
|
||||
'symbol': symbol,
|
||||
'gateway': gateway,
|
||||
'bar': True
|
||||
}
|
||||
self.settingDict[vtSymbol] = d
|
||||
else:
|
||||
d = self.settingDict[vtSymbol]
|
||||
d['bar'] = True
|
||||
|
||||
# 创建BarManager对象
|
||||
self.bgDict[vtSymbol] = BarGenerator(self.onBar)
|
||||
|
||||
# 主力合约记录配置
|
||||
if 'active' in drSetting:
|
||||
d = drSetting['active']
|
||||
self.activeSymbolDict = {vtSymbol:activeSymbol for activeSymbol, vtSymbol in d.items()}
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def getSetting(self):
|
||||
"""获取配置"""
|
||||
return self.settingDict, self.activeSymbolDict
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def procecssTickEvent(self, event):
|
||||
"""处理行情事件"""
|
||||
tick = event.dict_['data']
|
||||
vtSymbol = tick.vtSymbol
|
||||
|
||||
# 生成datetime对象
|
||||
if not tick.datetime:
|
||||
tick.datetime = datetime.strptime(' '.join([tick.date, tick.time]), '%Y%m%d %H:%M:%S.%f')
|
||||
|
||||
self.onTick(tick)
|
||||
|
||||
bm = self.bgDict.get(vtSymbol, None)
|
||||
if bm:
|
||||
bm.updateTick(tick)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onTick(self, tick):
|
||||
"""Tick更新"""
|
||||
vtSymbol = tick.vtSymbol
|
||||
|
||||
if vtSymbol in self.tickSymbolSet:
|
||||
self.insertData(TICK_DB_NAME, vtSymbol, tick)
|
||||
|
||||
if vtSymbol in self.activeSymbolDict:
|
||||
activeSymbol = self.activeSymbolDict[vtSymbol]
|
||||
self.insertData(TICK_DB_NAME, activeSymbol, tick)
|
||||
|
||||
|
||||
self.writeDrLog(text.TICK_LOGGING_MESSAGE.format(symbol=tick.vtSymbol,
|
||||
time=tick.time,
|
||||
last=tick.lastPrice,
|
||||
bid=tick.bidPrice1,
|
||||
ask=tick.askPrice1))
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onBar(self, bar):
|
||||
"""分钟线更新"""
|
||||
vtSymbol = bar.vtSymbol
|
||||
|
||||
self.insertData(MINUTE_DB_NAME, vtSymbol, bar)
|
||||
|
||||
if vtSymbol in self.activeSymbolDict:
|
||||
activeSymbol = self.activeSymbolDict[vtSymbol]
|
||||
self.insertData(MINUTE_DB_NAME, activeSymbol, bar)
|
||||
|
||||
self.writeDrLog(text.BAR_LOGGING_MESSAGE.format(symbol=bar.vtSymbol,
|
||||
time=bar.time,
|
||||
open=bar.open,
|
||||
high=bar.high,
|
||||
low=bar.low,
|
||||
close=bar.close))
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def registerEvent(self):
|
||||
"""注册事件监听"""
|
||||
self.eventEngine.register(EVENT_TICK, self.procecssTickEvent)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def insertData(self, dbName, collectionName, data):
|
||||
"""插入数据到数据库(这里的data可以是VtTickData或者VtBarData)"""
|
||||
self.queue.put((dbName, collectionName, data.__dict__))
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def run(self):
|
||||
"""运行插入线程"""
|
||||
while self.active:
|
||||
try:
|
||||
dbName, collectionName, d = self.queue.get(block=True, timeout=1)
|
||||
|
||||
# 这里采用MongoDB的update模式更新数据,在记录tick数据时会由于查询
|
||||
# 过于频繁,导致CPU占用和硬盘读写过高后系统卡死,因此不建议使用
|
||||
#flt = {'datetime': d['datetime']}
|
||||
#self.mainEngine.dbUpdate(dbName, collectionName, d, flt, True)
|
||||
|
||||
# 使用insert模式更新数据,可能存在时间戳重复的情况,需要用户自行清洗
|
||||
try:
|
||||
self.mainEngine.dbInsert(dbName, collectionName, d)
|
||||
except DuplicateKeyError:
|
||||
self.writeDrLog(u'键值重复插入失败,报错信息:' %traceback.format_exc())
|
||||
except Empty:
|
||||
pass
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def start(self):
|
||||
"""启动"""
|
||||
self.active = True
|
||||
self.thread.start()
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def stop(self):
|
||||
"""退出"""
|
||||
if self.active:
|
||||
self.active = False
|
||||
self.thread.join()
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def writeDrLog(self, content):
|
||||
"""快速发出日志事件"""
|
||||
log = VtLogData()
|
||||
log.logContent = content
|
||||
event = Event(type_=EVENT_DATARECORDER_LOG)
|
||||
event.dict_['data'] = log
|
||||
self.eventEngine.put(event)
|
||||
|
13
vnpy/trader/app/histDataCollector/language/__init__.py
Normal file
13
vnpy/trader/app/histDataCollector/language/__init__.py
Normal file
@ -0,0 +1,13 @@
|
||||
# encoding: UTF-8
|
||||
|
||||
import json
|
||||
import os
|
||||
import traceback
|
||||
|
||||
# 默认设置
|
||||
from chinese import text
|
||||
|
||||
# 是否要使用英文
|
||||
from vnpy.trader.vtGlobal import globalSetting
|
||||
if globalSetting['language'] == 'english':
|
||||
from english import text
|
16
vnpy/trader/app/histDataCollector/language/chinese/text.py
Normal file
16
vnpy/trader/app/histDataCollector/language/chinese/text.py
Normal file
@ -0,0 +1,16 @@
|
||||
# encoding: UTF-8
|
||||
|
||||
DATA_RECORDER = u'行情记录'
|
||||
|
||||
TICK_RECORD = u'Tick记录'
|
||||
BAR_RECORD = u'Bar记录'
|
||||
TICK_RECORD = u'Tick记录'
|
||||
|
||||
CONTRACT_SYMBOL = u'合约代码'
|
||||
GATEWAY = u'接口'
|
||||
|
||||
DOMINANT_CONTRACT = u'主力合约'
|
||||
DOMINANT_SYMBOL = u'主力代码'
|
||||
|
||||
TICK_LOGGING_MESSAGE = u'记录Tick数据{symbol},时间:{time}, last:{last}, bid:{bid}, ask:{ask}'
|
||||
BAR_LOGGING_MESSAGE = u'记录分钟线数据{symbol},时间:{time}, O:{open}, H:{high}, L:{low}, C:{close}'
|
15
vnpy/trader/app/histDataCollector/language/english/text.py
Normal file
15
vnpy/trader/app/histDataCollector/language/english/text.py
Normal file
@ -0,0 +1,15 @@
|
||||
# encoding: UTF-8
|
||||
|
||||
DATA_RECORDER = u'Data Recorder'
|
||||
|
||||
TICK_RECORD = u'Tick Record'
|
||||
BAR_RECORD = u'Bar Record'
|
||||
|
||||
CONTRACT_SYMBOL = u'Contract Symbol'
|
||||
GATEWAY = u'Gateway'
|
||||
|
||||
DOMINANT_CONTRACT = u'Dominant Contract'
|
||||
DOMINANT_SYMBOL = u'Dominant Symbol'
|
||||
|
||||
TICK_LOGGING_MESSAGE = u'Record Tick Data {symbol}, Time:{time}, last:{last}, bid:{bid}, ask:{ask}'
|
||||
BAR_LOGGING_MESSAGE = u'Record Bar Data {symbol}, Time:{time}, O:{open}, H:{high}, L:{low}, C:{close}'
|
Loading…
Reference in New Issue
Block a user