This commit is contained in:
msincenselee 2018-09-21 21:24:53 +08:00
parent d22986a2a9
commit 22180cf239
7 changed files with 2154 additions and 83 deletions

View File

@ -31,21 +31,33 @@ PERIOD_MAPPING['1month'] = '1M'
SYMBOL_LIST = ['ltc_btc', 'eth_btc', 'etc_btc', 'bch_btc', 'btc_usdt', 'eth_usdt', 'ltc_usdt', 'etc_usdt', 'bch_usdt',
'etc_eth','bt1_btc','bt2_btc','btg_btc','qtum_btc','hsr_btc','neo_btc','gas_btc',
'qtum_usdt','hsr_usdt','neo_usdt','gas_usdt']
'qtum_usdt','hsr_usdt','neo_usdt','gas_usdt','bnb_usdt','eos_usdt']
class BinanceData(object):
# ----------------------------------------------------------------------
def __init__(self, strategy):
def __init__(self, strategy=None):
"""
构造函数
:param strategy: 上层策略主要用与使用strategy.writeCtaLog
:param strategy: 上层策略主要用与使用writeLog
"""
self.strategy = strategy
self.client = Client('', '')
self.client = Client('-', '-')
def writeLog(self,content):
if self.strategy and hasattr(self.strategy,'writeCtaLog'):
self.strategy.writeCtaLog(content)
else:
print(content)
def get_bars(self, symbol, period, callback, bar_is_completed=False, bar_freq=1, start_dt=None):
def writeError(self,content):
if self.strategy and hasattr(self.strategy,'writeCtaError'):
self.strategy.writeCtaError(content)
else:
print(content,file=sys.stderr)
def get_bars(self, symbol, period, callback, bar_is_completed=False,bar_freq=1, start_dt=None):
"""
返回k线数据
symbol合约
@ -53,10 +65,10 @@ class BinanceData(object):
"""
ret_bars = []
if symbol not in SYMBOL_LIST:
self.strategy.writeCtaError(u'{} 合约{}不在下载清单中'.format(datetime.now(), symbol))
self.writeError(u'{} 合约{}不在下载清单中'.format(datetime.now(), symbol))
return False,ret_bars
if period not in PERIOD_MAPPING:
self.strategy.writeCtaError(u'{} 周期{}不在下载清单中'.format(datetime.now(), period))
self.writeError(u'{} 周期{}不在下载清单中'.format(datetime.now(), period))
return False,ret_bars
if self.client is None:
return False,ret_bars
@ -64,37 +76,107 @@ class BinanceData(object):
binance_symbol = symbol.upper().replace('_' , '')
binance_period = PERIOD_MAPPING.get(period)
self.strategy.writeCtaLog('{}开始下载binance:{} {}数据.'.format(datetime.now(), binance_symbol, binance_period))
self.writeLog('{}开始下载binance:{} {}数据.'.format(datetime.now(), binance_symbol, binance_period))
bars = []
try:
bars = self.client.get_klines(symbol=binance_symbol, interval=binance_period)
bar_len = len(bars)
for i, bar in enumerate(bars):
add_bar = CtaBarData()
try:
add_bar.vtSymbol = symbol
add_bar.symbol = symbol
add_bar.datetime = datetime.fromtimestamp(bar[0] / 1000)
utcdatetime = datetime.utcfromtimestamp(bar[0] / 1e3)
add_bar.date = add_bar.datetime.strftime('%Y-%m-%d')
add_bar.time = add_bar.datetime.strftime('%H:%M:%S')
add_bar.tradingDay = add_bar.date
# 币安的交易日是按照utc来计算的
add_bar.tradingDay = utcdatetime.strftime('%Y-%m-%d')
add_bar.open = float(bar[1])
add_bar.high = float(bar[2])
add_bar.low = float(bar[3])
add_bar.close = float(bar[4])
add_bar.volume = float(bar[5])
ret_bars.append(add_bar)
except Exception as ex:
self.strategy.writeCtaError(
self.writeError(
'error when convert bar:{},ex:{},t:{}'.format(bar, str(ex), traceback.format_exc()))
return False
return False,ret_bars
if start_dt is not None and bar.datetime < start_dt:
continue
ret_bars.append(add_bar)
if callback is not None:
callback(add_bar, bar_is_completed, bar_freq)
# 最后一个bar可能是不完整的强制修改
if i == bar_len -1 and bar_is_completed:
# 根据秒数算的话,要+1例如13:31,freq=31第31根bar
freq = int((datetime.now() - add_bar.datetime).total_seconds() / 60) + 1
callback(add_bar, False, freq)
else:
callback(add_bar, bar_is_completed, bar_freq)
return True,ret_bars
except Exception as ex:
self.strategy.writeCtaError('exception in get:{},{},{}'.format(binance_symbol,str(ex), traceback.format_exc()))
self.writeError('exception in get:{},{},{}'.format(binance_symbol,str(ex), traceback.format_exc()))
return False,ret_bars
def download_bars(self, symbol, period, start_dt=None):
"""
返回k线数据
symbol合约
period: 周期: 1min,3min,5min,15min,30min,1day,3day,1hour,2hour,4hour,6hour,12hour
"""
ret_bars = []
if symbol not in SYMBOL_LIST:
self.writeError(u'{} 合约{}不在下载清单中'.format(datetime.now(), symbol))
return ret_bars
if period not in PERIOD_MAPPING:
self.writeError(u'{} 周期{}不在下载清单中'.format(datetime.now(), period))
return ret_bars
if self.client is None:
return ret_bars
binance_symbol = symbol.upper().replace('_', '')
binance_period = PERIOD_MAPPING.get(period)
self.writeLog('{}开始下载binance:{} {}数据.'.format(datetime.now(), binance_symbol, binance_period))
try:
bars = self.client.get_klines(symbol=binance_symbol, interval=binance_period)
for i, bar in enumerate(bars):
add_bar = {}
try:
bar_datetime = datetime.fromtimestamp(bar[0] / 1e3)
utc_datetime = datetime.utcfromtimestamp(bar[0] / 1e3)
add_bar['datetime'] = bar_datetime.strftime('%Y-%m-%d %H:%M:%S')
add_bar['date'] = bar_datetime.strftime('%Y-%m-%d')
add_bar['time'] = bar_datetime.strftime('%H:%M:%S')
add_bar['open'] = float(bar[1])
add_bar['high'] = float(bar[2])
add_bar['low'] = float(bar[3])
add_bar['close'] = float(bar[4])
add_bar['volume'] = float(bar[5])
add_bar['tradingDay'] = utc_datetime.strftime('%Y-%m-%d')
ret_bars.append(add_bar)
except Exception as ex:
self.writeError(
'error when convert bar:{},ex:{},t:{}'.format(bar, str(ex), traceback.format_exc()))
return ret_bars
if start_dt is not None and bar_datetime < start_dt:
continue
return ret_bars
except Exception as ex:
self.writeError('exception in get:{},{},{}'.format(binance_symbol,str(ex), traceback.format_exc()))
return ret_bars
if __name__ == '__main__':
binance_data = BinanceData()
bars = binance_data.download_bars(symbol='bnb_usdt', period='1day')
for bar in bars:
print(bar['datetime'])

View File

@ -2,7 +2,7 @@
# 从okex下载数据
from datetime import datetime, timezone
import sys
import requests
import execjs
import traceback
@ -11,13 +11,13 @@ from vnpy.trader.app.ctaStrategy.ctaBase import CtaBarData, CtaTickData
period_list = ['1min','3min','5min','15min','30min','1day','1week','1hour','2hour','4hour','6hour','12hour']
symbol_list = ['ltc_btc','eth_btc','etc_btc','bch_btc','btc_usdt','eth_usdt','ltc_usdt','etc_usdt','bch_usdt',
'etc_eth','bt1_btc','bt2_btc','btg_btc','qtum_btc','hsr_btc','neo_btc','gas_btc',
'qtum_usdt','hsr_usdt','neo_usdt','gas_usdt','eos_usdt']
'qtum_usdt','hsr_usdt','neo_usdt','gas_usdt','eos_usdt','ada_usdt','xmr_usdt','zrx_usdt','zil_usdt']
class OkexData(object):
# ----------------------------------------------------------------------
def __init__(self, strategy):
def __init__(self, strategy=None):
"""
构造函数
:param strategy: 上层策略主要用与使用strategy.writeCtaLog
@ -29,6 +29,18 @@ class OkexData(object):
self.session = requests.session()
self.session.keep_alive = False
def writeLog(self,content):
if self.strategy and hasattr(self.strategy,'writeCtaLog'):
self.strategy.writeCtaLog(content)
else:
print(content)
def writeError(self,content):
if self.strategy:
self.strategy.writeCtaError(content)
else:
print(content,file=sys.stderr)
def get_bars(self, symbol, period, callback, bar_is_completed=False,bar_freq=1, start_dt=None):
"""
返回k线数据
@ -38,24 +50,24 @@ class OkexData(object):
ret_bars = []
if symbol not in symbol_list:
self.strategy.writeCtaError(u'{} {}不在下载清单中'.format(datetime.now(), symbol))
return False,ret_bars
return False,ret_bars
url = u'https://www.okex.com/api/v1/kline.do?symbol={}&type={}'.format(symbol, period)
self.strategy.writeCtaLog('{}开始下载:{} {}数据.URL:{}'.format(datetime.now(), symbol, period,url))
self.writeLog('{}开始下载:{} {}数据.URL:{}'.format(datetime.now(), symbol, period,url))
content = None
bars = []
try:
content = self.session.get(url).content.decode('gbk')
bars = execjs.eval(content)
except Exception as ex:
self.strategy.writeCtaError('exception in get:{},{},{}'.format(url,str(ex), traceback.format_exc()))
return False,ret_bars
bars = execjs.eval(content)
bar_len = len(bars)
for i, bar in enumerate(bars):
if len(bar) < 5:
self.strategy.writeCtaError('error when import bar:{}'.format(bar))
return False
return False,ret_bars
if i == 0:
continue
add_bar = CtaBarData()
@ -71,17 +83,116 @@ class OkexData(object):
add_bar.low = float(bar[3])
add_bar.close = float(bar[4])
add_bar.volume = float(bar[5])
ret_bars.append(add_bar)
except Exception as ex:
self.strategy.writeCtaError('error when convert bar:{},ex:{},t:{}'.format(bar, str(ex), traceback.format_exc()))
return False,ret_bars
if start_dt is not None and bar.datetime < start_dt:
continue
ret_bars.append(add_bar)
if callback is not None:
callback(add_bar, bar_is_completed, bar_freq)
# 最后一个bar可能是不完整的强制修改
if i == bar_len -1 and bar_is_completed:
# 根据秒数算的话,要+1例如13:31,freq=31第31根bar
freq = int((datetime.now() - add_bar.datetime).total_seconds()/60)+1
callback(add_bar,False,freq)
else:
callback(add_bar, bar_is_completed, bar_freq)
return True,ret_bars
def download_bars(self, symbol, period, size_=None, start_dt=None):
"""
返回k线数据
symbol合约
period: 周期: 1min,3min,5min,15min,30min,1day,3day,1hour,2hour,4hour,6hour,12hour
"""
ret_bars = []
if symbol not in symbol_list:
msg = u'{} {}不在下载清单中'.format(datetime.now(), symbol)
if self.strategy:
self.strategy.writeCtaError(msg)
else:
print(msg)
return ret_bars
url = u'https://www.okex.com/api/v1/kline.do?symbol={}&type={}'.format(symbol, period)
if isinstance(size_,int):
url = url + u'&size={}'.format(size_)
if start_dt is not None and isinstance(start_dt,datetime):
url = url + u'&since={}'.format(int(start_dt.timestamp()*1000))
self.writeLog('{}开始下载:{} {}数据.URL:{}'.format(datetime.now(), symbol, period,url))
content = None
try:
content = self.session.get(url).content.decode('gbk')
except Exception as ex:
self.writeError('exception in get:{},{},{}'.format(url,str(ex), traceback.format_exc()))
return ret_bars
bars = execjs.eval(content)
if not isinstance(bars,list):
self.writeError('返回数据不是list:{}'.format(content))
return ret_bars
for i, bar in enumerate(bars):
if len(bar) < 5:
self.writeError('error when get bar:{}'.format(bar))
return ret_bars
if i == 0:
continue
add_bar = {}
try:
bar_datetime= datetime.fromtimestamp(bar[0] / 1000)
add_bar['datetime'] = bar_datetime.strftime('%Y-%m-%d %H:%M:%S')
add_bar['date'] = bar_datetime.strftime('%Y-%m-%d')
add_bar['time'] = bar_datetime.strftime('%H:%M:%S')
add_bar['open'] = float(bar[1])
add_bar['high'] = float(bar[2])
add_bar['low'] = float(bar[3])
add_bar['close'] = float(bar[4])
add_bar['volume'] = float(bar[5])
except Exception as ex:
self.writeError('error when convert bar:{},ex:{},t:{}'.format(bar, str(ex), traceback.format_exc()))
ret_bars.append(add_bar)
return ret_bars
class TestStrategy(object):
def __init__(self):
self.minDiff = 1
self.shortSymbol = 'btc'
self.vtSymbol = 'btc'
self.TMinuteInterval = 1
def addBar(self,bar,bar_is_completed, bar_freq):
print(u'tradingDay:{},dt:{},{} o:{},h:{},l:{},c:{},v:{}'.format(bar.tradingDay, bar.datetime,bar.vtSymbol, bar.open, bar.high,
bar.low, bar.close, bar.volume))
def onBar(self, bar):
print(u'tradingDay:{},dt:{},{} o:{},h:{},l:{},c:{},v:{}'.format(bar.tradingDay,bar.datetime,bar.vtSymbol, bar.open, bar.high, bar.low, bar.close, bar.volume))
def writeCtaLog(self, content):
print(content)
def writeCtaError(self, content):
print(content)
if __name__ == '__main__':
t = TestStrategy()
ok_data = OkexData(t)
# 下载日线
#bars = ok_data.download_bars(symbol='btc_usdt', period='1day')
# 下载分钟
bars = ok_data.download_bars(symbol='btc_usdt', period='1min',start_dt=datetime.strptime('2017-06-01','%Y-%m-%d'))
for bar in bars:
print(bar['datetime'])

View File

@ -40,7 +40,10 @@ from vnpy.trader.vtFunction import todayDate, getJsonPath
from vnpy.trader.util_mail import sendmail
# 加载 strategy目录下所有的策略
from vnpy.trader.app.ctaStrategy.strategy import STRATEGY_CLASS
try:
from vnpy.trader.util_wechat import *
except:
print('import util_wechat fail')
MATRIX_DB_NAME = 'matrix' # 虚拟策略矩阵的数据库名称
POSITION_DISPATCH_COLL_NAME = 'position_dispatch' # 虚拟策略矩阵的策略调度配置collection名称
@ -148,7 +151,7 @@ class CtaEngine(object):
contract = self.mainEngine.getContract(vtSymbol)
if contract is None:
self.writeCtaError(
u'vtEngine.sendOrder取不到{}合约得信息,{}发送{}委托:{},v{}'.format(vtSymbol, strategy.name, orderType, price,
u'vtEngine.sendOrder取不到{}合约得信息,{}发送{}委托:{},v{}失败'.format(vtSymbol, strategy.name, orderType, price,
volume))
return ''
@ -256,12 +259,18 @@ class CtaEngine(object):
if strategy:
self.orderStrategyDict[vtOrderID] = strategy # 保存vtOrderID和策略的映射关系
self.writeCtaLog(u'策略%s发送委托,%s, %s%s%s@%s'
% (strategy.name, vtSymbol, req.offset, req.direction, volume, price))
msg = u'策略%s发送委托,%s, %s%s%s@%s' % (strategy.name, vtSymbol, req.offset, req.direction, volume, price)
self.writeCtaLog(msg)
else:
self.writeCtaLog(u'%s发送委托,%s, %s%s%s@%s'
% ('CtaEngine', vtSymbol, req.offset, req.direction, volume, price))
msg = u'%s发送委托,%s, %s%s%s@%s' % ('CtaEngine', vtSymbol, req.offset, req.direction, volume, price)
self.writeCtaLog(msg)
# 发送微信
try:
sendWeChatMsg(msg, target=self.ctaEngine.mainEngine.gatewayDetailList[0]['gatewayName'])
except:
pass
return vtOrderID
# ----------------------------------------------------------------------
@ -283,6 +292,13 @@ class CtaEngine(object):
req.sessionID = order.sessionID
req.orderID = order.orderID
self.mainEngine.cancelOrder(req, order.gatewayName)
# 发送微信
try:
msg = u'发送撤单指令,%s, %s%s' % (order.symbol, order.orderID, order.gatewayName)
sendWeChatMsg(msg, target=self.ctaEngine.mainEngine.gatewayDetailList[0]['gatewayName'])
except:
pass
else:
if order.status == STATUS_ALLTRADED:
self.writeCtaLog(u'委托单({0}已执行,无法撤销'.format(vtOrderID))
@ -326,6 +342,13 @@ class CtaEngine(object):
order.totalVolume - order.tradedVolume))
self.mainEngine.cancelOrder(req, order.gatewayName)
# 发送微信
try:
msg = u'撤销所有单,{}'.format(symbol)
sendWeChatMsg(msg, target=self.ctaEngine.mainEngine.gatewayDetailList[0]['gatewayName'])
except:
pass
# ----------------------------------------------------------------------
def sendStopOrder(self, vtSymbol, orderType, price, volume, strategy):
"""发停止单(本地实现)"""
@ -361,10 +384,14 @@ class CtaEngine(object):
self.stopOrderDict[stopOrderID] = so # 字典中不会删除
self.workingStopOrderDict[stopOrderID] = so # 字典中会删除
self.writeCtaLog(u'发停止单成功,'
u'Id:{0},Symbol:{1},Type:{2},Price:{3},Volume:{4}'
u'.'.format(stopOrderID, vtSymbol, orderType, price, volume))
msg = u'发停止单成功Id:{},Symbol:{},Type:{},Price:{},Volume:{}'.format(stopOrderID, vtSymbol, orderType, price, volume)
self.writeCtaLog(msg)
# 发送微信
try:
sendWeChatMsg(msg, target=self.ctaEngine.mainEngine.gatewayDetailList[0]['gatewayName'])
except:
pass
return stopOrderID
# ----------------------------------------------------------------------
@ -379,9 +406,21 @@ class CtaEngine(object):
so.status = STOPORDER_CANCELLED # STOPORDER_WAITING =》STOPORDER_CANCELLED
del self.workingStopOrderDict[stopOrderID] # 删除
self.writeCtaLog(u'撤销停止单:{0}成功.'.format(stopOrderID))
# 发送微信
try:
sendWeChatMsg(u'撤销停止单:{0}成功.'.format(stopOrderID), target=self.ctaEngine.mainEngine.gatewayDetailList[0]['gatewayName'])
except:
pass
return True
else:
self.writeCtaLog(u'撤销停止单:{0}失败不存在Id.'.format(stopOrderID))
# 发送微信
try:
sendWeChatMsg(u'撤销停止单:{0}失败不存在Id.'.format(stopOrderID), target=self.ctaEngine.mainEngine.gatewayDetailList[0]['gatewayName'])
except:
pass
return False
# ----------------------------------------------------------------------
@ -441,11 +480,13 @@ class CtaEngine(object):
ctaTick = CtaTickData()
d = ctaTick.__dict__
for key in d.keys():
d[key] = tick.__getattribute__(key)
if key in tick.__dict__:
d[key] = tick.__getattribute__(key)
if not ctaTick.datetime:
# 添加datetime字段
ctaTick.datetime = datetime.strptime(' '.join([tick.date, tick.time]), '%Y-%m-%d %H:%M:%S.%f')
tickDate = tick.date.replace('-', '')
ctaTick.datetime = datetime.strptime(' '.join([tickDate, tick.time]), '%Y%m%d %H:%M:%S.%f')
# 逐个推送到策略实例中
l = self.tickStrategyDict[tick.vtSymbol]
@ -735,6 +776,26 @@ class CtaEngine(object):
pass
self.mainEngine.writeCritical(content)
def sendAlertToWechat(self,content,target):
"""发送微信告警"""
gw = EMPTY_STRING
if len(self.mainEngine.connected_gw_names)>0:
gw = self.mainEngine.connected_gw_names[0]
else:
if len(self.mainEngine.gatewayDetailList) > 0:
d = self.mainEngine.gatewayDetailList[0]
if isinstance(d, dict):
gw = d.get('gatewayDisplayName','Gateway')
if len(gw)>0:
content = u'[gw:{}]{}'.format(gw,content)
try:
from vnpy.trader import util_wechat
self.writeCtaLog(u'发送微信通知:{}'.format(content))
util_wechat.sendWeChatMsg(content=content, target=target,level=util_wechat.WECHAT_LEVEL_DEBUG)
except Exception as ex:
self.writeCtaError(u'调用微信接口失败:{} {}'.format(str(ex), traceback.format_exc()))
def sendCtaSignal(self, source, symbol, direction, price, level):
"""发出交易信号"""
s = VtSignalData()
@ -850,8 +911,8 @@ class CtaEngine(object):
self.writeCtaLog(u'撤销运行中策略{}的强制清仓,恢复运行'.format(name))
return False
except Exception as ex:
self.writeCtaCritical(u'撤销运行中策略{}的强制清仓时异常:{}'.format(name, str(ex)))
traceback.print_exc()
self.writeCtaCritical(u'撤销运行中策略{}的强制清仓时异常:{},{}'.format(name, str(ex),traceback.format_exc()))
return False
else:
# 防止策略重名
@ -921,13 +982,21 @@ class CtaEngine(object):
# 自动初始化
if 'auto_init' in setting:
if setting['auto_init'] == True:
self.writeCtaLog(u'自动初始化策略')
self.initStrategy(name=name)
self.writeCtaLog(u'自动初始化策略:{}'.format(name))
try:
self.initStrategy(name=name)
except Exception as ex:
self.writeCtaCritical(u'初始化策略:{} 异常,{},{}'.format(name,str(ex),traceback.format_exc()))
return False
if 'auto_start' in setting:
if setting['auto_start'] == True:
self.writeCtaLog(u'自动启动策略')
self.startStrategy(name=name)
self.writeCtaLog(u'自动启动策略:{}'.format(name))
try:
self.startStrategy(name=name)
except Exception as ex:
self.writeCtaCritical(u'自动启动策略:{} 异常,{},{}'.format(name, str(ex), traceback.format_exc()))
return False
return True
def initStrategy(self, name, force=False):
@ -1593,7 +1662,7 @@ class CtaEngine(object):
:return:
"""
try:
with open(self.settingfilePath) as f:
with open(self.settingfilePath,'r',encoding='UTF-8') as f:
l = json.load(f)
for setting in l:
try:
@ -1761,9 +1830,13 @@ class CtaEngine(object):
# 发出日志
content =u'策略{}触发异常已停止.{}'.format(strategy.name,traceback.format_exc())
self.writeCtaLog(content)
self.writeCtaError(content)
self.mainEngine.writeCritical(content)
if hasattr(strategy,'backtesting') and hasattr(strategy,'wechat_source'):
if not strategy.backtesting and len(strategy.wechat_source)>0:
self.sendAlertToWechat(content=content,target=strategy.wechat_source)
# ----------------------------------------------------------------------
# 仓位持久化相关
def savePosition(self):
@ -2047,7 +2120,14 @@ class PositionBuffer(object):
self.shortYd = EMPTY_INT
self.frozen = EMPTY_FLOAT
# ----------------------------------------------------------------------
def toStr(self):
"""更新显示信息"""
str = u'long:{},yd:{},td:{}, short:{},yd:{},td:{}, fz:{};' \
.format(self.longPosition, self.longYd, self.longToday,
self.shortPosition, self.shortYd, self.shortToday,self.frozen)
return str
#----------------------------------------------------------------------
def updatePositionData(self, pos):
"""更新持仓数据"""

File diff suppressed because it is too large Load Diff

View File

@ -26,7 +26,7 @@ PERIOD_MINUTE = 'minute' # 分钟级别周期
PERIOD_HOUR = 'hour' # 小时级别周期
PERIOD_DAY = 'day' # 日级别周期
def getCtaBarByType(bar_type):
def getCtaBarClass(bar_type):
assert isinstance(bar_type,str)
if bar_type == PERIOD_SECOND:
return CtaLineBar
@ -39,6 +39,7 @@ def getCtaBarByType(bar_type):
raise Exception('no matched CTA bar type:{}'.format(bar_type))
class CtaLineBar(object):
"""CTA K线"""
""" 使用方法:
@ -125,6 +126,8 @@ class CtaLineBar(object):
self.lastTick = None
self.curTradingDay = EMPTY_STRING
self.cur_price = EMPTY_FLOAT
# K线保存数据
self.bar = None # K线数据对象
self.lineBar = [] # K线缓存数据队列
@ -472,16 +475,18 @@ class CtaLineBar(object):
self.writeCtaLog(u'竞价排名tick时间:{0}'.format(tick.datetime))
return
self.curTick = tick
self.curTick = copy.copy(tick)
if self.curTick.lastPrice is None or self.curTick.lastPrice == 0:
self.curTick.lastPrice = (self.curTick.askPrice1 + self.curTick.bidPrice1) / 2
self.cur_price = (self.curTick.askPrice1 + self.curTick.bidPrice1) / 2
else:
self.cur_price = self.curTick.lastPrice
# 3.生成x K线若形成新Bar则触发OnBar事件
self.drawLineBar(tick)
# 更新curPeriod的Highlow
if self.curPeriod is not None:
if self.curTick.lastPrice is None:
self.curTick.lastPrice = (self.curTick.askPrice1 + self.curTick.bidPrice1) / 2
self.curPeriod.onPrice(self.curTick.lastPrice)
# 4.执行 bar内计算
@ -498,6 +503,9 @@ class CtaLineBar(object):
"""
l1 = len(self.lineBar)
# 更新最后价格
self.cur_price = bar.close
if l1 == 0:
new_bar = copy.copy(bar)
self.lineBar.append(new_bar)
@ -2696,13 +2704,13 @@ class CtaLineBar(object):
self.skd_last_cross = (self.lineSK[-1] + self.lineSK[-2] + self.lineSD[-1] + self.lineSD[-2])/4
self.skd_rt_count = self.skd_count
self.skd_rt_last_cross = self.skd_last_cross
if self.skd_rt_cross_price == 0 or self.lineBar[-1].close < self.skd_rt_cross_price:
self.skd_rt_cross_price = self.lineBar[-1].close
self.skd_cross_price = min(self.lineBar[-1].close ,self.skd_rt_cross_price)
if self.skd_rt_cross_price == 0 or self.cur_price < self.skd_rt_cross_price:
self.skd_rt_cross_price = self.cur_price
self.skd_cross_price = self.cur_price
if self.skd_divergence < 0:
# 若原来是顶背离,消失
self.skd_divergence = 0
self.writeCtaLog(u'{} Gold Cross:{} at {}'.format(self.name, self.skd_last_cross, self.skd_cross_price))
else: #if self.lineSK[-1] < self.lineSK[-2]:
# 延续死叉
self.skd_count -= 1
@ -2722,14 +2730,16 @@ class CtaLineBar(object):
self.skd_last_cross = (self.lineSK[-1] + self.lineSK[-2] + self.lineSD[-1] + self.lineSD[-2]) / 4
self.skd_rt_count = self.skd_count
self.skd_rt_last_cross = self.skd_last_cross
if self.skd_rt_cross_price == 0 or self.lineBar[-1].close > self.skd_rt_cross_price:
self.skd_rt_cross_price = self.lineBar[-1].close
self.skd_cross_price = max(self.lineBar[-1].close, self.skd_rt_cross_price)
if self.skd_rt_cross_price == 0 or self.cur_price > self.skd_rt_cross_price:
self.skd_rt_cross_price = self.cur_price
self.skd_cross_price = self.cur_price
# 若原来是底背离,消失
if self.skd_divergence > 0:
self.skd_divergence = 0
self.writeCtaLog(u'{} Dead Cross:{} at {}'.format(self.name, self.skd_last_cross, self.skd_cross_price))
else: #if self.lineSK[-1] > self.lineSK[-2]:
# 延续金叉
self.skd_count += 1
@ -2909,7 +2919,9 @@ class CtaLineBar(object):
if self.skd_rt_count >= 0:
self.skd_rt_count = -1
self.skd_rt_last_cross = skd_last_cross
self.skd_rt_cross_price = self.lineBar[-1].close
self.skd_rt_cross_price = self.cur_price
self.writeCtaLog(u'{} rt Dead Cross at:{} ,price:{}'
.format(self.name, self.skd_rt_last_cross, self.skd_rt_cross_price))
if skd_last_cross > high_skd:
return True
@ -2942,8 +2954,9 @@ class CtaLineBar(object):
if self.skd_rt_count <=0:
self.skd_rt_count = 1
self.skd_rt_last_cross = skd_last_cross
self.skd_rt_cross_price = self.lineBar[-1].close
self.skd_rt_cross_price = self.cur_price
self.writeCtaLog(u'{} rt Gold Cross at:{} ,price:{}'
.format(self.name, self.skd_rt_last_cross,self.skd_rt_cross_price))
if skd_last_cross < low_skd:
return True
@ -3116,6 +3129,82 @@ class CtaLineBar(object):
return None
return None
def is_shadow_line(self,open, high, low, close, direction, shadow_rate, wave_rate):
"""
是否上影线/下影线
:param open: 开仓价
:param high: 最高价
:param low: 最低价
:param close: 收盘价
:param direction: 方向/
:param shadown_rate: 上影线比例百分比
:param wave_rate:振幅百分比
:return:
"""
if close<=0 or high <= low or shadow_rate <=0 or wave_rate <=0:
self.writeCtaLog(u'是否上下影线,参数出错.close={}, high={},low={},shadow_rate={},wave_rate={}'
.format(close, high, low, shadow_rate, wave_rate))
return False
# 振幅 = 高-低 / 收盘价 百分比
cur_wave_rate = round(100 * float((high - low) / close), 2)
# 上涨时,判断上影线
if direction == DIRECTION_LONG:
# 上影线比例 = 上影线(高- max开盘收盘/ 当日振幅=(高-低)
cur_shadow_rate = round(100 * float((high - max(open,close)) / (high-low)),2)
if cur_wave_rate >= wave_rate and cur_shadow_rate >= shadow_rate:
return True
# 下跌时,判断下影线
elif direction == DIRECTION_SHORT:
cur_shadow_rate = round(100 * float((min(open,close)-low) / (high-low)),2)
if cur_wave_rate >= wave_rate and cur_shadow_rate >= shadow_rate:
return True
return False
def is_end_tick(self, tick_dt):
"""
根据短合约和时间判断是否为最后一个tick
:param tick_dt:
:return:
"""
if self.is_7x24:
return False
# 中金所只有1130 和1515才有最后一个tick
if self.shortSymbol in MARKET_ZJ:
if (tick_dt.hour == 11 and tick_dt.minute == 30) or (tick_dt.hour == 15 and tick_dt.minute == 15):
return True
else:
return False
# 其他合约(上期所/郑商所/大连)
if 2 <= tick_dt.hour < 23:
if (tick_dt.hour == 10 and tick_dt.minute == 15) \
or (tick_dt.hour == 11 and tick_dt.minute == 30) \
or (tick_dt.hour == 15 and tick_dt.minute == 00) \
or (tick_dt.hour == 2 and tick_dt.minute == 30):
return True
else:
return False
# 夜盘1:30收盘
if self.shortSymbol in NIGHT_MARKET_SQ2 and tick_dt.hour == 1 and tick_dt.minute == 00:
return True
# 夜盘23:00收盘
if self.shortSymbol in NIGHT_MARKET_SQ3 and tick_dt.hour == 23 and tick_dt.minute == 00:
return True
# 夜盘23:30收盘
if self.shortSymbol in NIGHT_MARKET_ZZ or self.shortSymbol in NIGHT_MARKET_DL:
if tick_dt.hour == 23 and tick_dt.minute == 30:
return True
return False
class CtaMinuteBar(CtaLineBar):
"""
分钟级别K线
@ -3209,6 +3298,9 @@ class CtaMinuteBar(CtaLineBar):
if bar.tradingDay is None:
bar.tradingDay = self.getTradingDate(bar.datetime)
# 更新最后价格
self.cur_price = bar.close
l1 = len(self.lineBar)
if l1 == 0:
@ -3489,6 +3581,9 @@ class CtaHourBar(CtaLineBar):
if bar.tradingDay is None:
bar.tradingDay = self.getTradingDate(bar.datetime)
# 更新最后价格
self.cur_price = bar.close
l1 = len(self.lineBar)
if l1 == 0:
@ -3567,7 +3662,6 @@ class CtaHourBar(CtaLineBar):
endtick = False
if not self.is_7x24:
# 处理日内的间隔时段最后一个tick如10:15分11:30分15:00 和 2:30分
if (tick.datetime.hour == 10 and tick.datetime.minute == 15) \
or (tick.datetime.hour == 11 and tick.datetime.minute == 30) \
or (tick.datetime.hour == 15 and tick.datetime.minute == 00) \
@ -3590,10 +3684,22 @@ class CtaHourBar(CtaLineBar):
lastBar = self.lineBar[-1]
is_new_bar = False
if self.last_minute is None:
if tick.datetime.second == 0:
self.m1_bars_count += 1
self.last_minute = tick.datetime.minute
# 不在同一交易日推入新bar
if self.curTradingDay != tick.tradingDay:
is_new_bar = True
# 去除分钟和秒数
tick.datetime = datetime.strptime(tick.datetime.strftime('%Y-%m-%d %H:00:00'), '%Y-%m-%d %H:%M:%S')
tick.time = tick.datetime.strftime('%H:%M:%S')
self.curTradingDay = tick.tradingDay
self.writeCtaLog('{} drawLineBar() new_bar,{} curTradingDay:{},tick.tradingDay:{}'
.format(self.name, tick.datetime.strftime("%Y-%m-%d %H:%M:%S"), self.curTradingDay,
tick.tradingDay))
else:
# 同一交易日,看分钟是否一致
if tick.datetime.minute != self.last_minute and not endtick:
@ -3602,14 +3708,27 @@ class CtaHourBar(CtaLineBar):
if self.is_7x24:
if (tick.datetime - lastBar.datetime).total_seconds() >= 3600 * self.barTimeInterval:
self.writeCtaLog('{} drawLineBar() new_bar,{} - {} > 3600 * {} '
.format(self.name, tick.datetime.strftime("%Y-%m-%d %H:%M:%S"), lastBar.datetime.strftime("%Y-%m-%d %H:%M:%S"),
self.barTimeInterval))
is_new_bar = True
if len(tick.tradingDay) >0:
# 去除分钟和秒数
tick.datetime = datetime.strptime(tick.datetime.strftime('%Y-%m-%d %H:00:00'), '%Y-%m-%d %H:%M:%S')
tick.time = tick.datetime.strftime('%H:%M:%S')
if len(tick.tradingDay) > 0:
self.curTradingDay = tick.tradingDay
else:
self.curTradingDay = tick.date
if self.m1_bars_count > 60 * self.barTimeInterval:
self.writeCtaLog('{} drawLineBar() new_bar,{} {} > 60 * {} '
.format(self.name, tick.datetime.strftime("%Y-%m-%d %H:%M:%S"),
self.m1_bars_count,
self.barTimeInterval))
is_new_bar = True
# 去除秒数
tick.datetime = datetime.strptime(tick.datetime.strftime('%Y-%m-%d %H:%M:00'), '%Y-%m-%d %H:%M:%S')
tick.time = tick.datetime.strftime('%H:%M:%S')
if is_new_bar:
# 创建并推入新的Bar
@ -3741,6 +3860,9 @@ class CtaDayBar(CtaLineBar):
:param bar_freq, bar对象得frequency
:return:
"""
# 更新最后价格
self.cur_price = bar.close
l1 = len(self.lineBar)
if l1 == 0:

View File

@ -80,8 +80,6 @@ class BinanceGateway(VtGateway):
self.writeLog(u'BINANCE连接配置缺少字段请检查')
return
self.api_spot.active = True
if self.log_message:
@ -96,13 +94,15 @@ class BinanceGateway(VtGateway):
sub.symbol = symbol_pair
self.subscribe(sub)
self.writeLog(u'{}接口初始化成功'.format(self.gatewayName))
# 启动查询
self.initQuery()
self.startQuery()
def checkStatus(self):
return self.connected and self.api_spot.checkStatus()
# ----------------------------------------------------------------------
def subscribe(self, subscribeReq):
"""订阅行情,自动订阅全部行情,无需实现"""
@ -116,7 +116,7 @@ class BinanceGateway(VtGateway):
except Exception as ex:
self.writeError(u'send order Exception:{},{}'.format(str(ex),traceback.format_exc()))
#----------------------------------------------------------------------
# ----------------------------------------------------------------------
def cancelOrder(self, cancelOrderReq):
"""撤单"""
return self.api_spot.cancel(cancelOrderReq)
@ -418,6 +418,23 @@ print ex.status_code, ex.message , ex.code , ex.request , ex.uri , ex.kwargs
self.gateway.onContract(contract)
def checkStatus(self):
"""
检查接口状态:
若active为Falsereturn False
若active为True检查ticker得更新时间
:return:
"""
if not self.active:
return False
if len(self.tickDict.items())>0:
symbol,last_tick = list(self.tickDict.items())[0]
if last_tick.datetime and (datetime.now()-last_tick.datetime).total_seconds() > 60:
return False
return True
#----------------------------------------------------------------------
def onAllTicker(self,msg):
"""币安支持所有 ticker 同时socket过来"""
@ -459,6 +476,8 @@ print ex.status_code, ex.message , ex.code , ex.request , ex.uri , ex.kwargs
tick.askPrice5, tick.askVolume5 = [0 , 0]
tick.datetime , tick.date , tick.time = self.generateDateTime( float(msg["E"]))
utc_dt = datetime.utcfromtimestamp( float(msg["E"])/1e3)
tick.tradingDay = utc_dt.strftime('%Y-%m-%d')
self.gateway.onTick(tick)
#----------------------------------------------------------------------
@ -630,7 +649,8 @@ print ex.status_code, ex.message , ex.code , ex.request , ex.uri , ex.kwargs
self.gateway.writeLog(u'OnDepth {}'.format(traceback.format_exc()))
tick.datetime , tick.date, tick.time = self.generateDateTime(uu_time_stamp)
utc_dt = datetime.utcfromtimestamp(float(uu_time_stamp)/ 1e3)
tick.tradingDay = utc_dt.strftime('%Y-%m-%d')
# print tick.__dict__
self.gateway.onTick(tick)
#self.gateway.onTick(copy(tick))
@ -773,6 +793,10 @@ print ex.status_code, ex.message , ex.code , ex.request , ex.uri , ex.kwargs
'''
#----------------------------------------------------------------------
def onGetAccount(self, data, req, reqID):
if self.gateway and not self.gateway.connected:
self.gateway.connected = True
balances = data["balances"]
account = VtAccountData()
account.gatewayName = self.gatewayName
@ -1114,5 +1138,5 @@ BREAK
"""生成时间"""
dt = datetime.fromtimestamp(float(s)/1e3)
time = dt.strftime("%H:%M:%S.%f")
date = dt.strftime("%Y%m%d")
date = dt.strftime("%Y-%m-%d")
return dt , date, time

View File

@ -920,7 +920,7 @@ class OkexSpotApi(WsSpotApi):
tick.date, tick.time,tick.datetime = self.generateDateTime(data['timestamp'])
# print "Depth", tick.date, tick.time
tick.tradingDay = tick.date
# 推送tick事件
newtick = copy(tick)
self.gateway.onTick(newtick)