def update_account(self, dt, balance): """ 更新资金曲线 :param dt: :param balance: 账号级别,直接使用账号得的balance; :return: """ tick = TickData(gateway_name='Fund', symbol=self.symbol, exchange=Exchange.LOCAL, datetime=dt) tick.last_price = balance tick.volume = 1 tick.ask_price_1 = balance tick.ask_volume_1 = 1 tick.bid_price_1 = balance tick.bid_volume_1 = 1 tick.date = tick.datetime.strftime('%Y-%m-%d') tick.time = tick.datetime.strftime('%H:%M:%S') tick.trading_day = get_trading_date(dt) tick.open_interest = balance if self.inited: self.kline.on_tick(tick) # 如果是从账号更新,无法更新持仓盈亏 self.closed_profit = balance self.holding_profit = 0
def update_strategy(self, dt, closed_pnl=0, hold_pnl=0): """ 更新资金曲线 :param dt: :param closed_pnl: 策略提供的平仓盈亏 :param hold_pnl: 策略提供的持仓盈亏 :return: """ # 获取当前bar的平仓权益 open_interest = 0 if len(self.kline.line_bar) > 0: open_interest = self.kline.line_bar[-1].open_interest if closed_pnl != 0: self.write_log(u'策略平仓收益:{}->{}'.format(open_interest, open_interest + closed_pnl)) open_interest += closed_pnl tick = TickData(gateway_name='Fund', symbol=self.symbol, exchange=Exchange.LOCAL, datetime=dt) tick.last_price = open_interest + hold_pnl tick.volume = 1 tick.ask_price1 = open_interest + hold_pnl tick.ask_volume1 = 1 tick.bid_price1 = open_interest + hold_pnl tick.bid_volume1 = 1 tick.datetime = dt tick.open_interest = open_interest tick.date = tick.datetime.strftime('%Y-%m-%d') tick.time = tick.datetime.strftime('%H:%M:%S') tick.trading_day = get_trading_date(dt) if self.inited: self.kline.on_tick(tick) self.closed_profit = open_interest self.holding_profit = hold_pnl
def onRtnDepthMarketData(self, data: dict): """ Callback of tick data update. """ symbol = data["InstrumentID"] exchange = symbol_exchange_map.get(symbol, "") if not exchange: return timestamp = f"{data['ActionDay']} {data['UpdateTime']}.{int(data['UpdateMillisec']/100)}" dt = datetime.strptime(timestamp, "%Y%m%d %H:%M:%S.%f") # 不处理开盘前的tick数据 if dt.hour in [8, 20] and dt.minute < 59: return if exchange is Exchange.CFFEX and dt.hour == 9 and dt.minute < 14: return tick = TickData(symbol=symbol, exchange=exchange, datetime=dt, date=dt.strftime('%Y-%m-%d'), time=dt.strftime('%H:%M:%S.%f'), trading_day=get_trading_date(dt), name=symbol_name_map[symbol], volume=data["Volume"], open_interest=data["OpenInterest"], last_price=data["LastPrice"], limit_up=data["UpperLimitPrice"], limit_down=data["LowerLimitPrice"], open_price=adjust_price(data["OpenPrice"]), high_price=adjust_price(data["HighestPrice"]), low_price=adjust_price(data["LowestPrice"]), pre_close=adjust_price(data["PreClosePrice"]), bid_price_1=adjust_price(data["BidPrice1"]), ask_price_1=adjust_price(data["AskPrice1"]), bid_volume_1=data["BidVolume1"], ask_volume_1=data["AskVolume1"], gateway_name=self.gateway_name) if data["BidVolume2"] or data["AskVolume2"]: tick.bid_price_2 = adjust_price(data["BidPrice2"]) tick.bid_price_3 = adjust_price(data["BidPrice3"]) tick.bid_price_4 = adjust_price(data["BidPrice4"]) tick.bid_price_5 = adjust_price(data["BidPrice5"]) tick.ask_price_2 = adjust_price(data["AskPrice2"]) tick.ask_price_3 = adjust_price(data["AskPrice3"]) tick.ask_price_4 = adjust_price(data["AskPrice4"]) tick.ask_price_5 = adjust_price(data["AskPrice5"]) tick.bid_volume_2 = adjust_price(data["BidVolume2"]) tick.bid_volume_3 = adjust_price(data["BidVolume3"]) tick.bid_volume_4 = adjust_price(data["BidVolume4"]) tick.bid_volume_5 = adjust_price(data["BidVolume5"]) tick.ask_volume_2 = adjust_price(data["AskVolume2"]) tick.ask_volume_3 = adjust_price(data["AskVolume3"]) tick.ask_volume_4 = adjust_price(data["AskVolume4"]) tick.ask_volume_5 = adjust_price(data["AskVolume5"]) self.gateway.on_tick(tick)
def get_history_transaction_data(self, symbol, date, cache_folder=None): """获取当某一交易日的历史成交记录""" ret_datas = [] if isinstance(date, datetime): date = date.strftime('%Y%m%d') if isinstance(date, str): date = int(date) self.connect() cache_symbol = symbol cache_date = str(date) max_data_size = sys.maxsize symbol = symbol.upper() if '99' in symbol: # 查询的是指数合约 symbol = symbol.replace('99', 'L9') tdx_index_symbol = symbol else: # 查询的是普通合约 tdx_index_symbol = get_underlying_symbol(symbol).upper() + 'L9' q_size = QSIZE * 5 # 每秒 2个, 10小时 max_data_size = 1000000 # 优先从缓存加载 if cache_folder: buffer_data = self.load_cache(cache_folder, cache_symbol, cache_date) if buffer_data: self.write_log(u'使用缓存文件') return True, buffer_data self.write_log(u'开始下载{} 历史{}分笔数据'.format(date, symbol)) cur_trading_date = get_trading_date() if date == int(cur_trading_date.replace('-', '')): return self.get_transaction_data(symbol) try: _datas = [] _pos = 0 while (True): _res = self.api.get_history_transaction_data( market=self.symbol_market_dict.get(tdx_index_symbol, 0), date=date, code=symbol, start=_pos, count=q_size) if _res is not None: for d in _res: dt = d.pop('date') # 星期1~星期6 if dt.hour >= 20 and 1 < dt.isoweekday() <= 6: dt = dt - timedelta(days=1) d.update({'datetime': dt}) elif dt.hour >= 20 and dt.isoweekday() == 1: # 星期一取得20点后数据 dt = dt - timedelta(days=3) d.update({'datetime': dt}) elif dt.hour < 8 and dt.isoweekday() == 1: # 星期一取得8点前数据 dt = dt - timedelta(days=3) d.update({'datetime': dt}) elif dt.hour >= 20 and dt.isoweekday() == 7: # 星期天取得20点后数据,肯定是星期五夜盘 dt = dt - timedelta(days=2) d.update({'datetime': dt}) elif dt.isoweekday() == 7: # 星期日取得其他时间,必然是 星期六凌晨的数据 dt = dt - timedelta(days=1) d.update({'datetime': dt}) else: d.update({'datetime': dt}) # 接口有bug,返回价格*1000,所以要除以1000 d.update({'price': d.get('price', 0) / 1000}) _datas = sorted(_res, key=lambda s: s['datetime']) + _datas _pos += min(q_size, len(_res)) if _res is not None and len(_res) > 0: self.write_log(u'分段取分笔数据:{} ~{}, {}条,累计:{}条'.format( _res[0]['datetime'], _res[-1]['datetime'], len(_res), _pos)) else: break if len(_datas) >= max_data_size: break if len(_datas) == 0: self.write_error(u'{}分笔成交数据获取为空'.format(date)) return False, _datas # 缓存文件 if cache_folder: self.save_cache(cache_folder, cache_symbol, cache_date, _datas) return True, _datas except Exception as ex: self.write_error( 'exception in get_transaction_data:{},{},{}'.format( symbol, str(ex), traceback.format_exc())) self.write_error(u'当前异常服务器信息:{}'.format(self.best_ip)) self.write_log(u'重置连接') self.api = None self.connect(is_reconnect=True) return False, ret_datas
def load(self): """ 从本地csv文件恢复k线数据 :return: """ self.kline_file = str( get_folder_path('data').joinpath('fund_{}.csv'.format( self.kline_name))) # 如果数据文件存在,则加载数据 if os.path.exists(self.kline_file): self.write_log(u'加载{}数据'.format(self.kline_name)) df = pd.read_csv(self.kline_file) dt_now = datetime.now() df = df.set_index(pd.DatetimeIndex(df['datetime'])) for dt, bar_data in df.iterrows(): bar = BarData() bar.symbol = self.symbol bar.datetime = dt bar.open_price = float(bar_data['open']) bar.close_price = float(bar_data['close']) bar.high_price = float(bar_data['high']) bar.low_price = float(bar_data['low']) bar.date = dt.strftime('%Y-%m-%d') str_td = str(bar_data.get('trading_date', '')) if len(str_td) == 8: bar.trading_day = str_td[0:4] + '-' + str_td[ 4:6] + '-' + str_td[6:8] elif len(str_td) == 0: bar.trading_day = bar.date else: bar.trading_day = get_trading_date(dt) bar.time = dt.strftime('%H:%M:%S') bar.open_interest = float(bar_data.get('open_interest', 0)) if self.use_renko: self.kline.add_bar(bar) else: # bar得时间,与当前时间相隔超过一个小时,加入完整得bar if (dt_now - dt).total_seconds() > 60 * 60: self.kline.add_bar(bar, bar_is_completed=True, bar_freq=60) # 可能是最后一根bar else: self.write_log(u'更新最后一根Bar:{},now:{}'.format( dt, dt_now)) self.kline.add_bar(bar, bar_is_completed=False, bar_freq=dt.minute) else: self.write_log(u'当前没有资金历史K线文件:{}'.format(self.kline_file)) self.inited = True # 设置 kline的输出文件 self.kline.export_filename = self.kline_file self.kline.export_fields = [{ 'name': 'datetime', 'source': 'bar', 'attr': 'datetime', 'type_': 'datetime' }, { 'name': 'open', 'source': 'bar', 'attr': 'open_price', 'type_': 'float' }, { 'name': 'high', 'source': 'bar', 'attr': 'high_price', 'type_': 'float' }, { 'name': 'low', 'source': 'bar', 'attr': 'low_price', 'type_': 'float' }, { 'name': 'close', 'source': 'bar', 'attr': 'close_price', 'type_': 'float' }, { 'name': 'turnover', 'source': 'bar', 'attr': 'turnover', 'type_': 'float' }, { 'name': 'volume', 'source': 'bar', 'attr': 'volume', 'type_': 'float' }, { 'name': 'open_interest', 'source': 'bar', 'attr': 'open_interest', 'type_': 'float' }]