更新回测引擎
This commit is contained in:
parent
0af79fc28b
commit
fea6ce4aa9
@ -19,6 +19,7 @@ import csv
|
|||||||
from ctaBase import *
|
from ctaBase import *
|
||||||
from ctaSetting import *
|
from ctaSetting import *
|
||||||
|
|
||||||
|
from eventEngine import *
|
||||||
from vtConstant import *
|
from vtConstant import *
|
||||||
from vtGateway import VtOrderData, VtTradeData
|
from vtGateway import VtOrderData, VtTradeData
|
||||||
from vtFunction import loadMongoSetting
|
from vtFunction import loadMongoSetting
|
||||||
@ -36,7 +37,7 @@ class BacktestingEngine(object):
|
|||||||
2.修改装载数据为批量式后加载模式。
|
2.修改装载数据为批量式后加载模式。
|
||||||
3.增加csv 读取bar的回测模式
|
3.增加csv 读取bar的回测模式
|
||||||
4.增加csv 读取tick合并价差的回测模式
|
4.增加csv 读取tick合并价差的回测模式
|
||||||
|
5.增加EventEngine,并对newBar增加发送OnBar事件,供外部的回测主体显示Bar线。
|
||||||
"""
|
"""
|
||||||
|
|
||||||
TICK_MODE = 'tick' # 数据模式,逐Tick回测
|
TICK_MODE = 'tick' # 数据模式,逐Tick回测
|
||||||
@ -46,8 +47,11 @@ class BacktestingEngine(object):
|
|||||||
FINAL_MODE = 'Final' # 最后才统计交易,不适合按照百分比等开仓数量计算
|
FINAL_MODE = 'Final' # 最后才统计交易,不适合按照百分比等开仓数量计算
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
def __init__(self):
|
def __init__(self, eventEngine = None):
|
||||||
"""Constructor"""
|
"""Constructor"""
|
||||||
|
|
||||||
|
self.eventEngine = eventEngine
|
||||||
|
|
||||||
# 本地停止单编号计数
|
# 本地停止单编号计数
|
||||||
self.stopOrderCount = 0
|
self.stopOrderCount = 0
|
||||||
# stopOrderID = STOPORDERPREFIX + str(stopOrderCount)
|
# stopOrderID = STOPORDERPREFIX + str(stopOrderCount)
|
||||||
@ -698,8 +702,8 @@ class BacktestingEngine(object):
|
|||||||
leg1BidVolume1 = int(float(row['BidVolume']))
|
leg1BidVolume1 = int(float(row['BidVolume']))
|
||||||
|
|
||||||
# 排除涨停/跌停的数据
|
# 排除涨停/跌停的数据
|
||||||
if (leg1AskPrice1== float('1.79769E308') and leg1AskVolume1 == 0) \
|
if ((leg1AskPrice1 == float('1.79769E308') or leg1AskPrice1 == 0) and leg1AskVolume1 == 0) \
|
||||||
or (leg1BidPrice1 == float('1.79769E308') and leg1BidVolume1 == 0):
|
or ((leg1BidPrice1 == float('1.79769E308') or leg1BidPrice1 == 0) and leg1BidVolume1 == 0):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# 叫卖价差=leg1.askPrice1 - leg2.bidPrice1,volume为两者最小
|
# 叫卖价差=leg1.askPrice1 - leg2.bidPrice1,volume为两者最小
|
||||||
@ -951,7 +955,15 @@ class BacktestingEngine(object):
|
|||||||
|
|
||||||
self.output(u'数据回放结束')
|
self.output(u'数据回放结束')
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
def __sendOnBarEvent(self, bar):
|
||||||
|
"""发送Bar的事件"""
|
||||||
|
if self.eventEngine is not None:
|
||||||
|
eventType = EVENT_ON_BAR + '_' + self.symbol
|
||||||
|
event = Event(type_= eventType)
|
||||||
|
event.dict_['data'] = bar
|
||||||
|
self.eventEngine.put(event)
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------
|
||||||
def newBar(self, bar):
|
def newBar(self, bar):
|
||||||
"""新的K线"""
|
"""新的K线"""
|
||||||
self.bar = bar
|
self.bar = bar
|
||||||
@ -959,7 +971,8 @@ class BacktestingEngine(object):
|
|||||||
self.crossLimitOrder() # 先撮合限价单
|
self.crossLimitOrder() # 先撮合限价单
|
||||||
self.crossStopOrder() # 再撮合停止单
|
self.crossStopOrder() # 再撮合停止单
|
||||||
self.strategy.onBar(bar) # 推送K线到策略中
|
self.strategy.onBar(bar) # 推送K线到策略中
|
||||||
|
self.__sendOnBarEvent(bar) # 推送K线到事件
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
def newTick(self, tick):
|
def newTick(self, tick):
|
||||||
"""新的Tick"""
|
"""新的Tick"""
|
||||||
@ -1110,8 +1123,8 @@ class BacktestingEngine(object):
|
|||||||
# 遍历限价单字典中的所有限价单
|
# 遍历限价单字典中的所有限价单
|
||||||
for orderID, order in self.workingLimitOrderDict.items():
|
for orderID, order in self.workingLimitOrderDict.items():
|
||||||
# 判断是否会成交
|
# 判断是否会成交
|
||||||
buyCross = order.direction==DIRECTION_LONG and order.price>=buyCrossPrice
|
buyCross = order.direction==DIRECTION_LONG and order.price >= buyCrossPrice
|
||||||
sellCross = order.direction==DIRECTION_SHORT and order.price<=sellCrossPrice
|
sellCross = order.direction==DIRECTION_SHORT and order.price <= sellCrossPrice
|
||||||
|
|
||||||
# 如果发生了成交
|
# 如果发生了成交
|
||||||
if buyCross or sellCross:
|
if buyCross or sellCross:
|
||||||
@ -1159,6 +1172,7 @@ class BacktestingEngine(object):
|
|||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
self.writeCtaError(u'{0}:{1}'.format(Exception, ex))
|
self.writeCtaError(u'{0}:{1}'.format(Exception, ex))
|
||||||
|
|
||||||
|
# 实时计算模式
|
||||||
if self.calculateMode == self.REALTIME_MODE:
|
if self.calculateMode == self.REALTIME_MODE:
|
||||||
self.realtimeCalculate()
|
self.realtimeCalculate()
|
||||||
|
|
||||||
@ -1178,8 +1192,8 @@ class BacktestingEngine(object):
|
|||||||
# 遍历停止单字典中的所有停止单
|
# 遍历停止单字典中的所有停止单
|
||||||
for stopOrderID, so in self.workingStopOrderDict.items():
|
for stopOrderID, so in self.workingStopOrderDict.items():
|
||||||
# 判断是否会成交
|
# 判断是否会成交
|
||||||
buyCross = so.direction==DIRECTION_LONG and so.price<=buyCrossPrice
|
buyCross = so.direction==DIRECTION_LONG and so.price <= buyCrossPrice
|
||||||
sellCross = so.direction==DIRECTION_SHORT and so.price>=sellCrossPrice
|
sellCross = so.direction==DIRECTION_SHORT and so.price >= sellCrossPrice
|
||||||
|
|
||||||
# 如果发生了成交
|
# 如果发生了成交
|
||||||
if buyCross or sellCross:
|
if buyCross or sellCross:
|
||||||
@ -1283,6 +1297,7 @@ class BacktestingEngine(object):
|
|||||||
longid = EMPTY_STRING
|
longid = EMPTY_STRING
|
||||||
shortid = EMPTY_STRING
|
shortid = EMPTY_STRING
|
||||||
|
|
||||||
|
# 对交易记录逐一处理
|
||||||
for tradeid in self.tradeDict.keys():
|
for tradeid in self.tradeDict.keys():
|
||||||
trade = self.tradeDict[tradeid]
|
trade = self.tradeDict[tradeid]
|
||||||
# 多头交易
|
# 多头交易
|
||||||
@ -1423,8 +1438,8 @@ class BacktestingEngine(object):
|
|||||||
shortid = tradeid
|
shortid = tradeid
|
||||||
# 当前空头交易为平多
|
# 当前空头交易为平多
|
||||||
else:
|
else:
|
||||||
gId = tradeid # 交易组(多个平仓数为一组) s
|
gId = tradeid # 交易组(多个平仓数为一组) s
|
||||||
gr = None # 组合的交易结果
|
gr = None # 组合的交易结果
|
||||||
|
|
||||||
sellVolume = trade.volume
|
sellVolume = trade.volume
|
||||||
|
|
||||||
@ -1577,6 +1592,7 @@ class BacktestingEngine(object):
|
|||||||
self.writeCtaLog(msg)
|
self.writeCtaLog(msg)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# 对交易结果汇总统计
|
||||||
for time, result in resultDict.items():
|
for time, result in resultDict.items():
|
||||||
|
|
||||||
if result.pnl > 0:
|
if result.pnl > 0:
|
||||||
@ -1662,7 +1678,7 @@ class BacktestingEngine(object):
|
|||||||
groupId=gId, fixcommission=self.fixCommission)
|
groupId=gId, fixcommission=self.fixCommission)
|
||||||
|
|
||||||
if tv == 0:
|
if tv == 0:
|
||||||
if gt==1:
|
if gt == 1:
|
||||||
resultDict[entryTrade.dt] = result
|
resultDict[entryTrade.dt] = result
|
||||||
else:
|
else:
|
||||||
gr = copy.deepcopy(result)
|
gr = copy.deepcopy(result)
|
||||||
@ -1832,7 +1848,6 @@ class BacktestingEngine(object):
|
|||||||
for row in self.exportTradeList:
|
for row in self.exportTradeList:
|
||||||
writer.writerow(row)
|
writer.writerow(row)
|
||||||
|
|
||||||
|
|
||||||
def getResult(self):
|
def getResult(self):
|
||||||
# 返回回测结果
|
# 返回回测结果
|
||||||
d = {}
|
d = {}
|
||||||
|
@ -129,8 +129,8 @@ class CtaTickData(object):
|
|||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
"""Constructor"""
|
"""Constructor"""
|
||||||
self.vtSymbol = EMPTY_STRING # vt系统代码
|
self.vtSymbol = EMPTY_STRING # vt系统代码 CF705
|
||||||
self.symbol = EMPTY_STRING # 合约代码
|
self.symbol = EMPTY_STRING # 合约代码 CF1705
|
||||||
self.exchange = EMPTY_STRING # 交易所代码
|
self.exchange = EMPTY_STRING # 交易所代码
|
||||||
|
|
||||||
# 成交数据
|
# 成交数据
|
||||||
|
@ -15,6 +15,12 @@ import copy,csv
|
|||||||
|
|
||||||
DEBUGCTALOG = True
|
DEBUGCTALOG = True
|
||||||
|
|
||||||
|
PERIOD_SECOND = 'second' # 秒级别周期
|
||||||
|
PERIOD_MINUTE = 'minute' # 分钟级别周期
|
||||||
|
PERIOD_HOUR = 'hour' # 小时级别周期
|
||||||
|
PERIOD_DAY = 'day' # 日级别周期
|
||||||
|
|
||||||
|
|
||||||
class CtaLineBar(object):
|
class CtaLineBar(object):
|
||||||
"""CTA K线"""
|
"""CTA K线"""
|
||||||
""" 使用方法:
|
""" 使用方法:
|
||||||
@ -55,6 +61,7 @@ class CtaLineBar(object):
|
|||||||
|
|
||||||
# 参数列表
|
# 参数列表
|
||||||
self.paramList.append('barTimeInterval')
|
self.paramList.append('barTimeInterval')
|
||||||
|
self.paramList.append('period')
|
||||||
self.paramList.append('inputPreLen')
|
self.paramList.append('inputPreLen')
|
||||||
self.paramList.append('inputEma1Len')
|
self.paramList.append('inputEma1Len')
|
||||||
self.paramList.append('inputEma2Len')
|
self.paramList.append('inputEma2Len')
|
||||||
@ -72,6 +79,7 @@ class CtaLineBar(object):
|
|||||||
self.paramList.append('inputBollLen')
|
self.paramList.append('inputBollLen')
|
||||||
self.paramList.append('inputBollStdRate')
|
self.paramList.append('inputBollStdRate')
|
||||||
self.paramList.append('inputKdjLen')
|
self.paramList.append('inputKdjLen')
|
||||||
|
self.paramList.append('inputCciLen')
|
||||||
self.paramList.append('inputMacdFastPeriodLen')
|
self.paramList.append('inputMacdFastPeriodLen')
|
||||||
self.paramList.append('inputMacdSlowPeriodLen')
|
self.paramList.append('inputMacdSlowPeriodLen')
|
||||||
self.paramList.append('inputMacdSignalPeriodLen')
|
self.paramList.append('inputMacdSignalPeriodLen')
|
||||||
@ -83,9 +91,8 @@ class CtaLineBar(object):
|
|||||||
|
|
||||||
# 输入参数
|
# 输入参数
|
||||||
self.name = u'LineBar'
|
self.name = u'LineBar'
|
||||||
|
self.mode = self.TICK_MODE # 缺省为tick模式
|
||||||
self.mode = self.TICK_MODE
|
self.period = PERIOD_SECOND # 缺省为分钟级别周期
|
||||||
|
|
||||||
self.barTimeInterval = 300
|
self.barTimeInterval = 300
|
||||||
|
|
||||||
self.barMinuteInterval = self.barTimeInterval / 60
|
self.barMinuteInterval = self.barTimeInterval / 60
|
||||||
@ -117,6 +124,7 @@ class CtaLineBar(object):
|
|||||||
|
|
||||||
# 当前的Tick
|
# 当前的Tick
|
||||||
self.curTick = None
|
self.curTick = None
|
||||||
|
self.lastTick = None
|
||||||
self.curTradingDay = EMPTY_STRING
|
self.curTradingDay = EMPTY_STRING
|
||||||
|
|
||||||
# K 线服务的策略
|
# K 线服务的策略
|
||||||
@ -132,7 +140,6 @@ class CtaLineBar(object):
|
|||||||
self.preHigh = [] # K线的前inputPreLen的的最高
|
self.preHigh = [] # K线的前inputPreLen的的最高
|
||||||
self.preLow = [] # K线的前inputPreLen的的最低
|
self.preLow = [] # K线的前inputPreLen的的最低
|
||||||
|
|
||||||
|
|
||||||
self.lineMa1 = [] # K线的MA1均线,周期是InputMaLen1,不包含当前bar
|
self.lineMa1 = [] # K线的MA1均线,周期是InputMaLen1,不包含当前bar
|
||||||
self.lineMa2 = [] # K线的MA2均线,周期是InputMaLen2,不包含当前bar
|
self.lineMa2 = [] # K线的MA2均线,周期是InputMaLen2,不包含当前bar
|
||||||
|
|
||||||
@ -210,6 +217,9 @@ class CtaLineBar(object):
|
|||||||
self.lineKdjTop = [] # 记录KDJ最高峰,只保留 inputKdjLen个
|
self.lineKdjTop = [] # 记录KDJ最高峰,只保留 inputKdjLen个
|
||||||
self.lineKdjButtom = [] # 记录KDJ的最低谷,只保留 inputKdjLen个
|
self.lineKdjButtom = [] # 记录KDJ的最低谷,只保留 inputKdjLen个
|
||||||
self.lastKdjTopButtom = {} # 最近的一个波峰/波谷
|
self.lastKdjTopButtom = {} # 最近的一个波峰/波谷
|
||||||
|
self.lastK = EMPTY_FLOAT # bar内计算时,最后一个未关闭的bar的实时K值
|
||||||
|
self.lastD = EMPTY_FLOAT # bar内计算时,最后一个未关闭的bar的实时值
|
||||||
|
self.lastJ = EMPTY_FLOAT # bar内计算时,最后一个未关闭的bar的实时J值
|
||||||
|
|
||||||
# K线的MACD计算数据
|
# K线的MACD计算数据
|
||||||
self.inputMacdFastPeriodLen = EMPTY_INT
|
self.inputMacdFastPeriodLen = EMPTY_INT
|
||||||
@ -220,6 +230,10 @@ class CtaLineBar(object):
|
|||||||
self.lineDea = [] # DEA = (前一日DEA X 8/10 + 今日DIF X 2/10),即为talib-MACD返回值
|
self.lineDea = [] # DEA = (前一日DEA X 8/10 + 今日DIF X 2/10),即为talib-MACD返回值
|
||||||
self.lineMacd = [] # (dif-dea)*2,但是talib中MACD的计算是bar = (dif-dea)*1,国内一般是乘以2
|
self.lineMacd = [] # (dif-dea)*2,但是talib中MACD的计算是bar = (dif-dea)*1,国内一般是乘以2
|
||||||
|
|
||||||
|
# K 线的CCI计算数据
|
||||||
|
self.inputCciLen = EMPTY_INT
|
||||||
|
self.lineCci = []
|
||||||
|
|
||||||
if setting:
|
if setting:
|
||||||
self.setParam(setting)
|
self.setParam(setting)
|
||||||
|
|
||||||
@ -247,12 +261,19 @@ class CtaLineBar(object):
|
|||||||
if tick.datetime.hour == 8 or tick.datetime.hour == 20:
|
if tick.datetime.hour == 8 or tick.datetime.hour == 20:
|
||||||
self.writeCtaLog(u'竞价排名tick时间:{0}'.format(tick.datetime))
|
self.writeCtaLog(u'竞价排名tick时间:{0}'.format(tick.datetime))
|
||||||
return
|
return
|
||||||
|
if self.lastTick is None:
|
||||||
|
self.lastTick = tick
|
||||||
|
|
||||||
self.curTick = tick
|
self.curTick = tick
|
||||||
|
|
||||||
# 3.生成x K线,若形成新Bar,则触发OnBar事件
|
# 3.生成x K线,若形成新Bar,则触发OnBar事件
|
||||||
self.__drawLineBar(tick)
|
self.__drawLineBar(tick)
|
||||||
|
|
||||||
|
self.lastTick = tick
|
||||||
|
|
||||||
|
# 4.执行 bar内计算
|
||||||
|
self.__recountKdj(countInBar=True)
|
||||||
|
|
||||||
def addBar(self,bar):
|
def addBar(self,bar):
|
||||||
"""予以外部初始化程序增加bar"""
|
"""予以外部初始化程序增加bar"""
|
||||||
l1 = len(self.lineBar)
|
l1 = len(self.lineBar)
|
||||||
@ -268,7 +289,19 @@ class CtaLineBar(object):
|
|||||||
|
|
||||||
self.curTradingDay = bar.tradingDay
|
self.curTradingDay = bar.tradingDay
|
||||||
|
|
||||||
if abs((bar.datetime - lastBar.datetime).seconds) >= self.barTimeInterval:
|
if (self.period == PERIOD_SECOND and (bar.datetime-lastBar.datetime).seconds >= self.barTimeInterval) \
|
||||||
|
or (self.period == PERIOD_MINUTE and bar.datetime.minute % self.barTimeInterval == 0
|
||||||
|
and bar.datetime.minute != lastBar.datetime.minute) \
|
||||||
|
or (self.period == PERIOD_HOUR and self.barTimeInterval == 1 and bar.datetime
|
||||||
|
and bar.datetime.hour != lastBar.datetime.hour) \
|
||||||
|
or (self.period == PERIOD_HOUR and self.barTimeInterval == 2 and bar.datetime
|
||||||
|
and bar.datetime.hour != lastBar.datetime.hour
|
||||||
|
and bar.datetime.hour in {1, 9, 11, 13, 21, 23}) \
|
||||||
|
or (self.period == PERIOD_HOUR and self.barTimeInterval == 4 and bar.datetime
|
||||||
|
and bar.datetime.hour != lastBar.datetime.hour
|
||||||
|
and bar.datetime.hour in {1, 9, 13, 21}) \
|
||||||
|
or (self.period == PERIOD_DAY and bar.datetime.date != lastBar.datetime.date ):
|
||||||
|
|
||||||
self.lineBar.append(bar)
|
self.lineBar.append(bar)
|
||||||
self.onBar(bar)
|
self.onBar(bar)
|
||||||
return
|
return
|
||||||
@ -301,6 +334,7 @@ class CtaLineBar(object):
|
|||||||
self.__recountKdj()
|
self.__recountKdj()
|
||||||
self.__recountBoll()
|
self.__recountBoll()
|
||||||
self.__recountMacd()
|
self.__recountMacd()
|
||||||
|
self.__recountCci()
|
||||||
|
|
||||||
# 回调上层调用者
|
# 回调上层调用者
|
||||||
self.onBarFunc(bar)
|
self.onBarFunc(bar)
|
||||||
@ -360,6 +394,9 @@ class CtaLineBar(object):
|
|||||||
round(self.lineD[-1], 2),
|
round(self.lineD[-1], 2),
|
||||||
round(self.lineJ[-1], 2))
|
round(self.lineJ[-1], 2))
|
||||||
|
|
||||||
|
if self.inputCciLen > 0 and len(self.lineCci) > 0:
|
||||||
|
msg = msg + u',Cci({0}):{1}'.format(self.inputCciLen, self.lineCci[-1])
|
||||||
|
|
||||||
if self.inputBollLen > 0 and len(self.lineUpperBand)>0:
|
if self.inputBollLen > 0 and len(self.lineUpperBand)>0:
|
||||||
msg = msg + u',Boll({0}):u:{1},m:{2},l:{3}'.\
|
msg = msg + u',Boll({0}):u:{1},m:{2},l:{3}'.\
|
||||||
format(self.inputBollLen, round(self.lineUpperBand[-1], 2),
|
format(self.inputBollLen, round(self.lineUpperBand[-1], 2),
|
||||||
@ -376,7 +413,7 @@ class CtaLineBar(object):
|
|||||||
|
|
||||||
self.bar = CtaBarData() # 创建新的K线
|
self.bar = CtaBarData() # 创建新的K线
|
||||||
# 计算K线的整点分钟周期,这里周期最小是1分钟。如果你是采用非整点分钟,例如1.5分钟,请把这段注解掉
|
# 计算K线的整点分钟周期,这里周期最小是1分钟。如果你是采用非整点分钟,例如1.5分钟,请把这段注解掉
|
||||||
if self.barMinuteInterval:
|
if self.barMinuteInterval and self.period == PERIOD_SECOND:
|
||||||
self.barMinuteInterval = int(self.barTimeInterval / 60)
|
self.barMinuteInterval = int(self.barTimeInterval / 60)
|
||||||
if self.barMinuteInterval < 1:
|
if self.barMinuteInterval < 1:
|
||||||
self.barMinuteInterval = 1
|
self.barMinuteInterval = 1
|
||||||
@ -414,8 +451,6 @@ class CtaLineBar(object):
|
|||||||
# bar的交易日与记录的当前交易日一致, 交易量为tick的volume,减去上一根bar的日总交易量
|
# bar的交易日与记录的当前交易日一致, 交易量为tick的volume,减去上一根bar的日总交易量
|
||||||
self.bar.volume = tick.volume - self.lineBar[-1].dayVolume
|
self.bar.volume = tick.volume - self.lineBar[-1].dayVolume
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
self.barFirstTick = True # 标识该Tick属于该Bar的第一个tick数据
|
self.barFirstTick = True # 标识该Tick属于该Bar的第一个tick数据
|
||||||
|
|
||||||
self.lineBar.append(self.bar) # 推入到lineBar队列
|
self.lineBar.append(self.bar) # 推入到lineBar队列
|
||||||
@ -438,62 +473,6 @@ class CtaLineBar(object):
|
|||||||
# 与最后一个BAR的时间比对,判断是否超过5分钟
|
# 与最后一个BAR的时间比对,判断是否超过5分钟
|
||||||
lastBar = self.lineBar[-1]
|
lastBar = self.lineBar[-1]
|
||||||
|
|
||||||
# 专门处理隔夜跳空。隔夜跳空会造成开盘后EMA和ADX的计算错误。
|
|
||||||
if len(self.lineAtr2) < 1:
|
|
||||||
priceInBar = 5 * self.minDiff
|
|
||||||
else:
|
|
||||||
priceInBar = self.lineAtr2[-1]
|
|
||||||
|
|
||||||
jumpBars = int(abs(tick.lastPrice - lastBar.close)/priceInBar)
|
|
||||||
|
|
||||||
# 开盘时间
|
|
||||||
if (tick.datetime.hour == 9 or tick.datetime.hour == 21) \
|
|
||||||
and tick.datetime.minute == 0 and tick.datetime.second == 0 \
|
|
||||||
and lastBar.datetime.hour != tick.datetime.hour \
|
|
||||||
and jumpBars > 0 and self.activeDayJump:
|
|
||||||
|
|
||||||
priceInYesterday = lastBar.close
|
|
||||||
|
|
||||||
self.writeCtaLog(u'line Bar jumpbars:{0}'.format(jumpBars))
|
|
||||||
|
|
||||||
if tick.lastPrice > priceInYesterday: # 价格往上跳
|
|
||||||
|
|
||||||
# 生成砖块递增K线,减小ATR变动
|
|
||||||
for i in range(0, jumpBars, 1):
|
|
||||||
upbar = copy.deepcopy(lastBar)
|
|
||||||
upbar.open = priceInYesterday + float(i * priceInBar)
|
|
||||||
upbar.low = upbar.open
|
|
||||||
upbar.close = priceInYesterday + float((i+1) * priceInBar)
|
|
||||||
upbar.high = upbar.close
|
|
||||||
upbar.volume = 0
|
|
||||||
|
|
||||||
self.lineBar.append(upbar)
|
|
||||||
self.onBar(upbar)
|
|
||||||
|
|
||||||
else: # 价格往下跳
|
|
||||||
# 生成递减K线,减小ATR变动
|
|
||||||
for i in range(0, jumpBars, 1):
|
|
||||||
|
|
||||||
downbar = copy.deepcopy(lastBar)
|
|
||||||
downbar.open = priceInYesterday - float(i * priceInBar)
|
|
||||||
downbar.high = downbar.open
|
|
||||||
downbar.close = priceInYesterday - float((i+1) * priceInBar)
|
|
||||||
downbar.low = downbar.close
|
|
||||||
downbar.volume = 0
|
|
||||||
|
|
||||||
self.lineBar.append(downbar)
|
|
||||||
self.onBar(downbar)
|
|
||||||
|
|
||||||
# 生成平移K线,减小Pdi,Mdi、ADX变动
|
|
||||||
for i in range(0, jumpBars*2, 1):
|
|
||||||
equalbar=copy.deepcopy(self.lineBar[-1])
|
|
||||||
equalbar.volume = 0
|
|
||||||
self.lineBar.append(equalbar)
|
|
||||||
self.onBar(equalbar)
|
|
||||||
|
|
||||||
# 重新指定为最后一个Bar
|
|
||||||
lastBar = self.lineBar[-1]
|
|
||||||
|
|
||||||
# 处理日内的间隔时段最后一个tick,如10:15分,11:30分,15:00 和 2:30分
|
# 处理日内的间隔时段最后一个tick,如10:15分,11:30分,15:00 和 2:30分
|
||||||
endtick = False
|
endtick = False
|
||||||
if (tick.datetime.hour == 10 and tick.datetime.minute == 15) \
|
if (tick.datetime.hour == 10 and tick.datetime.minute == 15) \
|
||||||
@ -514,8 +493,31 @@ class CtaLineBar(object):
|
|||||||
if tick.datetime.hour == 23 and tick.datetime.minute == 30:
|
if tick.datetime.hour == 23 and tick.datetime.minute == 30:
|
||||||
endtick = True
|
endtick = True
|
||||||
|
|
||||||
# 满足时间要求,tick的时间,距离最后一个bar的开始时间,已经超出bar的时间周期(barTimeInterval),并且不是最后一个结束tick
|
# 满足时间要求
|
||||||
if (tick.datetime-lastBar.datetime).seconds >= self.barTimeInterval and not endtick:
|
# 1,秒周期,tick的时间,距离最后一个bar的开始时间,已经超出bar的时间周期(barTimeInterval)
|
||||||
|
# 2,分钟、小时周期,取整=0
|
||||||
|
# 3、日周期,开盘时间
|
||||||
|
# 4、不是最后一个结束tick
|
||||||
|
if ((self.period == PERIOD_SECOND and (tick.datetime-lastBar.datetime).seconds >= self.barTimeInterval) \
|
||||||
|
or
|
||||||
|
(self.period == PERIOD_MINUTE and tick.datetime.minute % self.barTimeInterval == 0
|
||||||
|
and tick.datetime.minute != self.lastTick.datetime.minute)
|
||||||
|
or
|
||||||
|
(self.period == PERIOD_HOUR and self.barTimeInterval == 1 and tick.datetime
|
||||||
|
and tick.datetime.hour != self.lastTick.datetime.hour)
|
||||||
|
or
|
||||||
|
(self.period == PERIOD_HOUR and self.barTimeInterval == 2 and tick.datetime
|
||||||
|
and tick.datetime.hour != self.lastTick.datetime.hour
|
||||||
|
and tick.datetime.hour in {1, 9, 11, 13, 21, 23})
|
||||||
|
or
|
||||||
|
(self.period == PERIOD_HOUR and self.barTimeInterval == 4 and tick.datetime
|
||||||
|
and tick.datetime.hour != self.lastTick.datetime.hour
|
||||||
|
and tick.datetime.hour in {1, 9, 13, 21})
|
||||||
|
or (self.period == PERIOD_DAY and tick.datetime
|
||||||
|
and (tick.datetime.hour == 21 or tick.datetime.hour == 9)
|
||||||
|
and 14 <= self.lastTick.datetime.hour <= 15)
|
||||||
|
) and not endtick:
|
||||||
|
|
||||||
# 创建并推入新的Bar
|
# 创建并推入新的Bar
|
||||||
self.__firstTick(tick)
|
self.__firstTick(tick)
|
||||||
# 触发OnBar事件
|
# 触发OnBar事件
|
||||||
@ -1136,7 +1138,7 @@ class CtaLineBar(object):
|
|||||||
self.lastBollLower = l - l % self.minDiff # 下轨取整
|
self.lastBollLower = l - l % self.minDiff # 下轨取整
|
||||||
|
|
||||||
|
|
||||||
def __recountKdj(self):
|
def __recountKdj(self, countInBar = False):
|
||||||
"""KDJ指标"""
|
"""KDJ指标"""
|
||||||
"""
|
"""
|
||||||
KDJ指标的中文名称又叫随机指标,是一个超买超卖指标,最早起源于期货市场,由乔治·莱恩(George Lane)首创。
|
KDJ指标的中文名称又叫随机指标,是一个超买超卖指标,最早起源于期货市场,由乔治·莱恩(George Lane)首创。
|
||||||
@ -1158,18 +1160,24 @@ class CtaLineBar(object):
|
|||||||
if self.inputKdjLen <= EMPTY_INT: return
|
if self.inputKdjLen <= EMPTY_INT: return
|
||||||
|
|
||||||
if len(self.lineBar) < self.inputKdjLen+1:
|
if len(self.lineBar) < self.inputKdjLen+1:
|
||||||
self.debugCtaLog(u'数据未充分,当前Bar数据数量:{0},计算KDJ需要:{1}'.format(len(self.lineBar), self.inputKdjLen+1))
|
if not countInBar:
|
||||||
|
self.debugCtaLog(u'数据未充分,当前Bar数据数量:{0},计算KDJ需要:{1}'.format(len(self.lineBar), self.inputKdjLen+1))
|
||||||
return
|
return
|
||||||
|
|
||||||
if self.mode == self.TICK_MODE:
|
# 数据是Tick模式,非bar内计算
|
||||||
|
if self.mode == self.TICK_MODE and not countInBar:
|
||||||
listClose =[x.close for x in self.lineBar[-self.inputKdjLen-1:-1]]
|
listClose =[x.close for x in self.lineBar[-self.inputKdjLen-1:-1]]
|
||||||
|
listHigh = [x.high for x in self.lineBar[-self.inputKdjLen - 1:-1]]
|
||||||
|
listLow = [x.low for x in self.lineBar[-self.inputKdjLen - 1:-1]]
|
||||||
idx = 2
|
idx = 2
|
||||||
else:
|
else:
|
||||||
listClose =[x.close for x in self.lineBar[-self.inputKdjLen:]]
|
listClose =[x.close for x in self.lineBar[-self.inputKdjLen:]]
|
||||||
|
listHigh = [x.high for x in self.lineBar[-self.inputKdjLen :]]
|
||||||
|
listLow = [x.low for x in self.lineBar[-self.inputKdjLen :]]
|
||||||
idx = 1
|
idx = 1
|
||||||
|
|
||||||
hhv = max(listClose)
|
hhv = max(listHigh)
|
||||||
llv = min(listClose)
|
llv = min(listLow)
|
||||||
|
|
||||||
if len(self.lineK) > 0:
|
if len(self.lineK) > 0:
|
||||||
lastK = self.lineK[-1]
|
lastK = self.lineK[-1]
|
||||||
@ -1184,7 +1192,7 @@ class CtaLineBar(object):
|
|||||||
if hhv == llv:
|
if hhv == llv:
|
||||||
rsv = 50
|
rsv = 50
|
||||||
else:
|
else:
|
||||||
rsv= (self.lineBar[-1].close - llv)/(hhv - llv) * 100
|
rsv = (self.lineBar[-1].close - llv)/(hhv - llv) * 100
|
||||||
|
|
||||||
k = 2*lastK/3 + rsv/3
|
k = 2*lastK/3 + rsv/3
|
||||||
if k < 0: k = 0
|
if k < 0: k = 0
|
||||||
@ -1196,6 +1204,12 @@ class CtaLineBar(object):
|
|||||||
|
|
||||||
j = 3*k - 2*d
|
j = 3*k - 2*d
|
||||||
|
|
||||||
|
if countInBar:
|
||||||
|
self.lastD = d
|
||||||
|
self.lastK = k
|
||||||
|
self.lastJ = j
|
||||||
|
return
|
||||||
|
|
||||||
if len(self.lineK) > self.inputKdjLen * 8:
|
if len(self.lineK) > self.inputKdjLen * 8:
|
||||||
del self.lineK[0]
|
del self.lineK[0]
|
||||||
self.lineK.append(k)
|
self.lineK.append(k)
|
||||||
@ -1238,7 +1252,6 @@ class CtaLineBar(object):
|
|||||||
self.lineKdjButtom.append(b)
|
self.lineKdjButtom.append(b)
|
||||||
self.lastKdjTopButtom = self.lineKdjButtom[-1]
|
self.lastKdjTopButtom = self.lineKdjButtom[-1]
|
||||||
|
|
||||||
|
|
||||||
def __recountMacd(self):
|
def __recountMacd(self):
|
||||||
"""
|
"""
|
||||||
Macd计算方法:
|
Macd计算方法:
|
||||||
@ -1258,7 +1271,7 @@ class CtaLineBar(object):
|
|||||||
|
|
||||||
maxLen = max(self.inputMacdFastPeriodLen,self.inputMacdSlowPeriodLen)+self.inputMacdSignalPeriodLen+1
|
maxLen = max(self.inputMacdFastPeriodLen,self.inputMacdSlowPeriodLen)+self.inputMacdSignalPeriodLen+1
|
||||||
|
|
||||||
maxLen = maxLen * 3 # 注:数据长度需要足够,才能准确。测试过,3倍长度才可以与国内的文华等软件一致
|
#maxLen = maxLen * 3 # 注:数据长度需要足够,才能准确。测试过,3倍长度才可以与国内的文华等软件一致
|
||||||
|
|
||||||
if len(self.lineBar) < maxLen:
|
if len(self.lineBar) < maxLen:
|
||||||
self.debugCtaLog(u'数据未充分,当前Bar数据数量:{0},计算MACD需要:{1}'.format(len(self.lineBar), maxLen))
|
self.debugCtaLog(u'数据未充分,当前Bar数据数量:{0},计算MACD需要:{1}'.format(len(self.lineBar), maxLen))
|
||||||
@ -1289,6 +1302,56 @@ class CtaLineBar(object):
|
|||||||
del self.lineMacd[0]
|
del self.lineMacd[0]
|
||||||
self.lineMacd.append(macd[-1]*2) # 国内一般是2倍
|
self.lineMacd.append(macd[-1]*2) # 国内一般是2倍
|
||||||
|
|
||||||
|
def __recountCci(self):
|
||||||
|
"""CCI计算
|
||||||
|
顺势指标又叫CCI指标,CCI指标是美国股市技术分析 家唐纳德·蓝伯特(Donald Lambert)于20世纪80年代提出的,专门测量股价、外汇或者贵金属交易
|
||||||
|
是否已超出常态分布范围。属于超买超卖类指标中较特殊的一种。波动于正无穷大和负无穷大之间。但是,又不需要以0为中轴线,这一点也和波动于正无穷大
|
||||||
|
和负无穷大的指标不同。
|
||||||
|
它最早是用于期货市场的判断,后运用于股票市场的研判,并被广泛使用。与大多数单一利用股票的收盘价、开盘价、最高价或最低价而发明出的各种技术分析
|
||||||
|
指标不同,CCI指标是根据统计学原理,引进价格与固定期间的股价平均区间的偏离程度的概念,强调股价平均绝对偏差在股市技术分析中的重要性,是一种比
|
||||||
|
较独特的技术指标。
|
||||||
|
它与其他超买超卖型指标又有自己比较独特之处。象KDJ、W%R等大多数超买超卖型指标都有“0-100”上下界限,因此,它们对待一般常态行情的研判比较适用
|
||||||
|
,而对于那些短期内暴涨暴跌的股票的价格走势时,就可能会发生指标钝化的现象。而CCI指标却是波动于正无穷大到负无穷大之间,因此不会出现指标钝化现
|
||||||
|
象,这样就有利于投资者更好地研判行情,特别是那些短期内暴涨暴跌的非常态行情。
|
||||||
|
http://baike.baidu.com/view/53690.htm?fromtitle=CCI%E6%8C%87%E6%A0%87&fromid=4316895&type=syn
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
if self.inputCciLen <= 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
# 1、lineBar满足长度才执行计算
|
||||||
|
if len(self.lineBar) < self.inputCciLen+2:
|
||||||
|
self.debugCtaLog(u'数据未充分,当前Bar数据数量:{0},计算CCI需要:{1}'.
|
||||||
|
format(len(self.lineBar), self.inputCciLen + 2))
|
||||||
|
return
|
||||||
|
|
||||||
|
# 计算第1根RSI曲线
|
||||||
|
|
||||||
|
# 3、inputCc1Len(包含当前周期)
|
||||||
|
if self.mode == self.TICK_MODE:
|
||||||
|
listClose = [x.close for x in self.lineBar[-self.inputCciLen - 2:-1]]
|
||||||
|
listHigh = [x.high for x in self.lineBar[-self.inputCciLen - 2:-1]]
|
||||||
|
listLow = [x.low for x in self.lineBar[-self.inputCciLen - 2:-1]]
|
||||||
|
idx = 2
|
||||||
|
else:
|
||||||
|
listClose = [x.close for x in self.lineBar[-self.inputCciLen-1:]]
|
||||||
|
listHigh = [x.high for x in self.lineBar[-self.inputCciLen - 1:]]
|
||||||
|
listLow = [x.low for x in self.lineBar[-self.inputCciLen - 1:]]
|
||||||
|
idx = 1
|
||||||
|
|
||||||
|
barCci = ta.CCI(high=numpy.array(listHigh, dtype=float), low=numpy.array(listLow, dtype=float),
|
||||||
|
close=numpy.array(listClose, dtype=float), timeperiod=self.inputCciLen)[-1]
|
||||||
|
|
||||||
|
barCci = round(float(barCci), 3)
|
||||||
|
|
||||||
|
l = len(self.lineCci)
|
||||||
|
if l > self.inputCciLen*8:
|
||||||
|
del self.lineCci[0]
|
||||||
|
|
||||||
|
self.lineCci.append(barCci)
|
||||||
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------------
|
# ----------------------------------------------------------------------
|
||||||
def writeCtaLog(self, content):
|
def writeCtaLog(self, content):
|
||||||
"""记录CTA日志"""
|
"""记录CTA日志"""
|
||||||
|
@ -18,29 +18,22 @@ class CtaPosition:
|
|||||||
self.strategy = strategy
|
self.strategy = strategy
|
||||||
|
|
||||||
self.pos = 0 # 持仓状态 0:空仓 >=1 多仓 <=-1 空仓
|
self.pos = 0 # 持仓状态 0:空仓 >=1 多仓 <=-1 空仓
|
||||||
|
|
||||||
self.maxPos = 1 # 最大持仓量
|
self.maxPos = 1 # 最大持仓量
|
||||||
|
|
||||||
self.step = 1 # 增仓数量
|
self.step = 1 # 增仓数量
|
||||||
|
|
||||||
self.posList = []
|
self.posList = []
|
||||||
|
|
||||||
|
|
||||||
self.avgPrice = EMPTY_FLOAT
|
self.avgPrice = EMPTY_FLOAT
|
||||||
|
|
||||||
def avaliablePos2Add(self):
|
def avaliablePos2Add(self):
|
||||||
"""剩余可加的仓位数量"""
|
"""剩余可加的仓位数量"""
|
||||||
|
|
||||||
return self.maxPos - abs(self.pos)
|
return self.maxPos - abs(self.pos)
|
||||||
|
|
||||||
def openPos(self, direction, vol, price = EMPTY_FLOAT):
|
def openPos(self, direction, vol, price = EMPTY_FLOAT):
|
||||||
"""开、加仓"""
|
"""开、加仓"""
|
||||||
|
|
||||||
if self.pos == 0:
|
if self.pos == 0:
|
||||||
self.posList = []
|
self.posList = []
|
||||||
|
|
||||||
if direction == DIRECTION_LONG: # 加多仓
|
if direction == DIRECTION_LONG: # 加多仓
|
||||||
|
|
||||||
if self.pos + vol > self.maxPos:
|
if self.pos + vol > self.maxPos:
|
||||||
self.writeCtaLog(u'异常,超出仓位,当前仓位:{0},加仓:{1},最大仓位:{2}'.format(self.pos,vol,self.maxPos))
|
self.writeCtaLog(u'异常,超出仓位,当前仓位:{0},加仓:{1},最大仓位:{2}'.format(self.pos,vol,self.maxPos))
|
||||||
return False
|
return False
|
||||||
@ -49,9 +42,7 @@ class CtaPosition:
|
|||||||
self.pos = self.pos + vol
|
self.pos = self.pos + vol
|
||||||
self.strategy.pos = self.pos
|
self.strategy.pos = self.pos
|
||||||
|
|
||||||
|
|
||||||
if direction == DIRECTION_SHORT: # 加空仓
|
if direction == DIRECTION_SHORT: # 加空仓
|
||||||
|
|
||||||
if self.pos - vol < 0 - self.maxPos:
|
if self.pos - vol < 0 - self.maxPos:
|
||||||
self.writeCtaLog(u'异常,超出仓位,当前仓位:{0},加仓:{1},最大仓位:{2}'.format(self.pos, vol, self.maxPos))
|
self.writeCtaLog(u'异常,超出仓位,当前仓位:{0},加仓:{1},最大仓位:{2}'.format(self.pos, vol, self.maxPos))
|
||||||
return False
|
return False
|
||||||
|
@ -13,10 +13,14 @@
|
|||||||
from strategy22_ArbitrageGrid import Strategy22
|
from strategy22_ArbitrageGrid import Strategy22
|
||||||
from strategy24_M15RB import Strategy24
|
from strategy24_M15RB import Strategy24
|
||||||
from strategy25_NonStdArbitrageGrid import Strategy25
|
from strategy25_NonStdArbitrageGrid import Strategy25
|
||||||
|
from strategy26_ArbitrageM1 import Strategy26
|
||||||
|
from strategy27_MultiPeriod import Strategy27
|
||||||
|
|
||||||
STRATEGY_CLASS = {}
|
STRATEGY_CLASS = {}
|
||||||
#STRATEGY_CLASS['DataRecorder'] = DataRecorder
|
#STRATEGY_CLASS['DataRecorder'] = DataRecorder
|
||||||
#STRATEGY_CLASS['DoubleEmaDemo'] = DoubleEmaDemo
|
#STRATEGY_CLASS['DoubleEmaDemo'] = DoubleEmaDemo
|
||||||
STRATEGY_CLASS['Strategy22'] = Strategy22
|
STRATEGY_CLASS['Strategy22'] = Strategy22
|
||||||
STRATEGY_CLASS['Strategy24'] = Strategy24
|
STRATEGY_CLASS['Strategy24'] = Strategy24
|
||||||
STRATEGY_CLASS['Strategy25'] = Strategy25
|
STRATEGY_CLASS['Strategy25'] = Strategy25
|
||||||
|
STRATEGY_CLASS['Strategy26'] = Strategy26
|
||||||
|
STRATEGY_CLASS['Strategy27'] = Strategy27
|
@ -1,214 +0,0 @@
|
|||||||
# encoding: UTF-8
|
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
'''一个简单的SINA数据客户端,主要使用requests开发'''
|
|
||||||
import requests
|
|
||||||
from time import sleep
|
|
||||||
import execjs
|
|
||||||
from datetime import datetime,timedelta
|
|
||||||
from ctaBase import CtaBarData,CtaTickData
|
|
||||||
|
|
||||||
class SinaClient(object):
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------------
|
|
||||||
def __init__(self, strategy):
|
|
||||||
|
|
||||||
self.strategy = strategy
|
|
||||||
|
|
||||||
requests.adapters.DEFAULT_RETRIES = 5
|
|
||||||
self.session = requests.session()
|
|
||||||
self.session.keep_alive = False
|
|
||||||
|
|
||||||
def getTicks(self, symbol, callback):
|
|
||||||
|
|
||||||
# 从sina加载最新的M1数据
|
|
||||||
try:
|
|
||||||
|
|
||||||
url = u'http://stock2.finance.sina.com.cn/futures/api/json.php/InnerFuturesService.getInnerFutures5MLine?symbol={0}'.format(
|
|
||||||
symbol)
|
|
||||||
self.strategy.writeCtaLog(u'从sina下载{0}Tick数据 {1}'.format(symbol, url))
|
|
||||||
responses = execjs.eval(self.session.get(url).content.decode('gbk').split('\n')[-1])
|
|
||||||
|
|
||||||
datevalue = datetime.now().strftime('%Y-%m-%d')
|
|
||||||
|
|
||||||
for j, day_item in enumerate(responses[str(symbol).upper()]):
|
|
||||||
for i, item in enumerate(day_item):
|
|
||||||
|
|
||||||
tick = CtaTickData()
|
|
||||||
tick.vtSymbol = symbol
|
|
||||||
tick.symbol = symbol
|
|
||||||
|
|
||||||
if len(item) >= 6:
|
|
||||||
datevalue = item[6]
|
|
||||||
|
|
||||||
tick.date = datevalue
|
|
||||||
tick.time = item[4] + u':00'
|
|
||||||
tick.datetime = datetime.strptime(tick.date + ' ' + tick.time, '%Y-%m-%d %H:%M:%S')
|
|
||||||
|
|
||||||
tick.lastPrice = float(item[0])
|
|
||||||
tick.volume = int(item[2])
|
|
||||||
|
|
||||||
if type(item[3]) == type(None):
|
|
||||||
tick.openInterest = 0
|
|
||||||
else:
|
|
||||||
tick.openInterest = int(item[3])
|
|
||||||
|
|
||||||
callback(tick)
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
self.strategy.writeCtaLog(u'加载sina历史Tick数据失败:' + str(e))
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def getMinBars(self, symbol, minute, callback):
|
|
||||||
"""# 从sina加载最新的M5,M15,M30,M60数据"""
|
|
||||||
|
|
||||||
if minute not in {5, 15, 30, 60}:
|
|
||||||
return False
|
|
||||||
|
|
||||||
sinaBars = []
|
|
||||||
try:
|
|
||||||
|
|
||||||
url = u'http://stock2.finance.sina.com.cn/futures/api/json.php/InnerFuturesService.getInnerFutures{0}MinKLine?symbol={1}'.format(minute,symbol)
|
|
||||||
self.strategy.writeCtaLog(u'从sina下载{0}的{1}分钟数据 {2}'.format(symbol,minute, url))
|
|
||||||
responses = execjs.eval(self.session.get(url).content.decode('gbk').split('\n')[-1])
|
|
||||||
dayVolume = 0
|
|
||||||
|
|
||||||
for item in responses:
|
|
||||||
bar = CtaBarData()
|
|
||||||
|
|
||||||
bar.vtSymbol = symbol
|
|
||||||
bar.symbol = symbol
|
|
||||||
# bar的close time
|
|
||||||
sinaDt = datetime.strptime(item[0], '%Y-%m-%d %H:%M:00')
|
|
||||||
|
|
||||||
if minute in {5, 15} and sinaDt.hour == 10 and sinaDt.minute == 30:
|
|
||||||
# 这个是sina的bug,它把10:15 ~10:30也包含进来了
|
|
||||||
continue
|
|
||||||
|
|
||||||
if minute == 60 and sinaDt.hour in {11,23,1,2} and sinaDt.minute == 30:
|
|
||||||
bar.datetime = sinaDt - timedelta(seconds=(minute /2)* 60)
|
|
||||||
else:
|
|
||||||
bar.datetime = sinaDt - timedelta(seconds=minute * 60)
|
|
||||||
|
|
||||||
bar.date = bar.datetime.strftime('%Y%m%d')
|
|
||||||
bar.tradingDay = bar.date # todo: 需要修改,晚上21点后,修改为next workingday
|
|
||||||
bar.time = bar.datetime.strftime('%H:%M:00')
|
|
||||||
|
|
||||||
bar.open = float(item[1])
|
|
||||||
bar.high = float(item[2])
|
|
||||||
bar.low = float(item[3])
|
|
||||||
bar.close = float(item[4])
|
|
||||||
bar.volume = int(item[5])
|
|
||||||
|
|
||||||
# 计算dayvolume
|
|
||||||
if not sinaBars:
|
|
||||||
dayVolume = bar.volume
|
|
||||||
else:
|
|
||||||
if sinaBars[-1].datetime.hour == 14 and bar.datetime.hour !=14:
|
|
||||||
dayVolume = bar.volume
|
|
||||||
else:
|
|
||||||
dayVolume += bar.volume
|
|
||||||
|
|
||||||
bar.dayVolume = dayVolume
|
|
||||||
|
|
||||||
sinaBars.append(bar)
|
|
||||||
|
|
||||||
if len(sinaBars)>0:
|
|
||||||
self.strategy.writeCtaLog(u'从sina读取了{0}条{1}分钟数据'.format(len(sinaBars),minute))
|
|
||||||
|
|
||||||
# 把sina的bar灌入回调函数
|
|
||||||
for bar in sinaBars:
|
|
||||||
callback(bar)
|
|
||||||
|
|
||||||
# 处理完毕,清空
|
|
||||||
sinaBars = []
|
|
||||||
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
self.strategy.writeCtaLog(u'从sina读取{0}分钟数据失败'.format(minute))
|
|
||||||
return False
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
self.strategy.writeCtaLog(u'加载Sina历史分钟数据失败:'+str(e))
|
|
||||||
return False
|
|
||||||
|
|
||||||
def getDayBars(self, symbol, callback):
|
|
||||||
"""# 从sina加载最新的Day数据"""
|
|
||||||
|
|
||||||
sinaBars = []
|
|
||||||
|
|
||||||
try:
|
|
||||||
|
|
||||||
url = u'http://stock.finance.sina.com.cn/futures/api/json.php/InnerFuturesService.getInnerFuturesDailyKLine?symbol={0}'.format(symbol)
|
|
||||||
self.strategy.writeCtaLog(u'从sina下载{0}的日K数据 {1}'.format(symbol, url))
|
|
||||||
responses = execjs.eval(self.session.get(url).content.decode('gbk'))
|
|
||||||
dayVolume = 0
|
|
||||||
|
|
||||||
for item in responses:
|
|
||||||
bar = CtaBarData()
|
|
||||||
|
|
||||||
bar.vtSymbol = symbol
|
|
||||||
bar.symbol = symbol
|
|
||||||
# bar的close time
|
|
||||||
bar.datetime = datetime.strptime(item['date'], '%Y-%m-%d')
|
|
||||||
bar.date = bar.datetime.strftime('%Y%m%d')
|
|
||||||
bar.tradingDay = bar.date # todo: 需要修改,晚上21点后,修改为next workingday
|
|
||||||
bar.time = bar.datetime.strftime('%H:%M:00')
|
|
||||||
|
|
||||||
bar.open = float(item['open'])
|
|
||||||
bar.high = float(item['high'])
|
|
||||||
bar.low = float(item['low'])
|
|
||||||
bar.close = float(item['close'])
|
|
||||||
bar.volume = int(item['volume'])
|
|
||||||
bar.dayVolume = bar.volume
|
|
||||||
|
|
||||||
sinaBars.append(bar)
|
|
||||||
|
|
||||||
if len(sinaBars)>0:
|
|
||||||
self.strategy.writeCtaLog(u'从sina读取了{0}条日线K数据'.format(len(sinaBars)))
|
|
||||||
|
|
||||||
# 把sina的bar灌入回调函数
|
|
||||||
for bar in sinaBars:
|
|
||||||
callback(bar)
|
|
||||||
|
|
||||||
# 处理完毕,清空
|
|
||||||
sinaBars = []
|
|
||||||
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
self.strategy.writeCtaLog(u'从sina读取日线K数据失败')
|
|
||||||
return False
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
self.strategy.writeCtaLog(u'加载Sina历史日线数据失败:'+str(e))
|
|
||||||
return False
|
|
||||||
|
|
||||||
class TestStrategy(object):
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def addBar(self, bar):
|
|
||||||
print(u'{0},o:{1},h:{2},l:{3},c:{4},v:{5}'.format(bar.datetime, bar.open, bar.high, bar.low, bar.close, bar.volume))
|
|
||||||
|
|
||||||
def addTick(self, tick):
|
|
||||||
print(u'{0},{1},ap:{2},av:{3},bp:{4},bv:{5}'.format(tick.datetime, tick.lastPrice, tick.askPrice1, tick.askVolume1, tick.bidPrice1, tick.bidVolume1))
|
|
||||||
|
|
||||||
def writeCtaLog(self, content):
|
|
||||||
print(content)
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
t = TestStrategy()
|
|
||||||
|
|
||||||
sina = SinaClient(t)
|
|
||||||
|
|
||||||
#rt=sina.getDayBars(symbol='RB1705', callback=t.addBar)
|
|
||||||
|
|
||||||
#rt = sina.getMinBars(symbol='RB1705',minute = 5, callback=t.addBar)
|
|
||||||
|
|
||||||
rt = sina.getTicks(symbol='RB1705', callback=t.addTick)
|
|
||||||
|
|
@ -4,6 +4,8 @@
|
|||||||
CTA模块相关的GUI控制组件
|
CTA模块相关的GUI控制组件
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
import sys
|
||||||
|
sys.path.append('..')
|
||||||
|
|
||||||
from uiBasicWidget import QtGui, QtCore, BasicCell
|
from uiBasicWidget import QtGui, QtCore, BasicCell
|
||||||
from eventEngine import *
|
from eventEngine import *
|
||||||
@ -19,7 +21,7 @@ class CtaValueMonitor(QtGui.QTableWidget):
|
|||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
"""Constructor"""
|
"""Constructor"""
|
||||||
super(CtaValueMonitor, self).__init__(parent)
|
super(CtaValueMonitor, self).__init__(parent)
|
||||||
|
|
||||||
self.keyCellDict = {}
|
self.keyCellDict = {}
|
||||||
self.data = None
|
self.data = None
|
||||||
self.inited = False
|
self.inited = False
|
||||||
@ -39,9 +41,12 @@ class CtaValueMonitor(QtGui.QTableWidget):
|
|||||||
def updateData(self, data):
|
def updateData(self, data):
|
||||||
"""更新数据"""
|
"""更新数据"""
|
||||||
if not self.inited:
|
if not self.inited:
|
||||||
|
# 设置标题
|
||||||
|
|
||||||
self.setColumnCount(len(data))
|
self.setColumnCount(len(data))
|
||||||
self.setHorizontalHeaderLabels(data.keys())
|
self.setHorizontalHeaderLabels(data.keys())
|
||||||
|
|
||||||
|
# 新增数据
|
||||||
col = 0
|
col = 0
|
||||||
for k, v in data.items():
|
for k, v in data.items():
|
||||||
cell = QtGui.QTableWidgetItem(unicode(v))
|
cell = QtGui.QTableWidgetItem(unicode(v))
|
||||||
@ -51,10 +56,14 @@ class CtaValueMonitor(QtGui.QTableWidget):
|
|||||||
|
|
||||||
self.inited = True
|
self.inited = True
|
||||||
else:
|
else:
|
||||||
|
# 更新数据
|
||||||
for k, v in data.items():
|
for k, v in data.items():
|
||||||
cell = self.keyCellDict[k]
|
cell = self.keyCellDict[k]
|
||||||
cell.setText(unicode(v))
|
cell.setText(unicode(v))
|
||||||
|
|
||||||
|
#cell.setBackgroundColor()
|
||||||
|
|
||||||
|
# 调整表格宽度为自适应
|
||||||
self.resizeColumnsToContents()
|
self.resizeColumnsToContents()
|
||||||
self.resizeRowsToContents()
|
self.resizeRowsToContents()
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user