async def handle_ws_data(*args, **kwargs): """ callback function Args: args: values kwargs: key-values. """ try: dict = {"data": ("callback param", *args)} # print(dict['data'][1]) if "topic" in dict['data'][1]: topic = dict['data'][1]['topic'] if "position" in topic: if 'data' in dict['data'][1]: data = dict['data'][1]['data'][0] if 'contract_code' in data: contract_code = data['contract_code'] amount = data['volume'] price = data['cost_hold'] direction = data['direction'] last = data['last_price'] leverage = data['lever_rate'] info = "【交易提醒】HUOBI交割合约持仓更新!合约ID:{} 持仓方向:{} 持仓量:{} 持仓均价:{} 最新成交价:{} 杠杆倍数:{}".format( contract_code, direction, amount, price, last, leverage) if dict['data'][1]['event'] == 'order.match' or dict[ 'data'][1]['event'] == 'settlement' or dict[ 'data'][1]['event'] == 'order.liquidation': push(info) else: if config.mongodb_console == "true": print("callback param", *args, **kwargs) dict = {"data": ("callback param", *args)} storage.mongodb_save(dict, config.mongodb_database, config.mongodb_collection) except: pass
def begin_trade(self, kline=None): try: if self.indicators.CurrentBar(kline=kline) < self.slow_length: # 如果k线数据不够长就返回 return timestamp = ts_to_datetime_str(utctime_str_to_ts(kline[-1][0])) if kline else get_localtime() # 非回测模式下时间戳就是当前本地时间 # 计算策略信号 ma = self.indicators.MA(self.fast_length, self.slow_length, kline=kline) fast_ma = ma[0] slow_ma = ma[1] cross_over = fast_ma[-2] >= slow_ma[-2] and fast_ma[-3] < slow_ma[-3] # 不用当根k线上的ma来计算信号,防止信号闪烁 cross_below = slow_ma[-2] >= fast_ma[-2] and slow_ma[-3] < fast_ma[-3] if self.indicators.BarUpdate(kline=kline): # 如果k线更新,计数器归零 self.counter = 0 if self.counter < 1: # 按照策略信号开平仓 if cross_over: # 金叉时 if self.position.amount() == 0: # 若当前无持仓,则买入开多并推送下单结果 price = self.market.open(-1, kline=kline) # 下单价格=此根k线收盘价 amount = round(self.total_asset / self.contract_value) # 数量=总资金/价格/合约面值 info = self.exchange.buy(price, amount) push(info) storage.mysql_save_strategy_run_info(self.database, self.datasheet, timestamp, "买入开多", price, amount, amount * self.contract_value, price, "long", amount, 0, self.total_profit, self.total_asset) # 将信息保存至数据库 if self.position.direction() == 'short': # 若当前持空头,先平空再开多 profit = self.position.covershort_profit(market_type="usd_contract", last=self.market.open(-1, kline=kline)) # 在平空前先计算逻辑盈亏,当前最新成交价为开盘价 self.total_profit += profit self.total_asset += profit # 计算此次盈亏后的总资金 cover_short_price = self.market.open(-1, kline=kline) cover_short_amount = self.position.amount() open_long_price = self.market.open(-1, kline=kline) open_long_amount = round(self.total_asset / self.contract_value) info = self.exchange.BUY(cover_short_price, cover_short_amount, open_long_price, open_long_amount) push("此次盈亏:{} 当前总资金:{}".format(profit, self.total_asset) + str(info)) # 需将返回的下单结果info转换为字符串后进行拼接 storage.mysql_save_strategy_run_info(self.database, self.datasheet, timestamp, "平空开多", open_long_price, open_long_amount, open_long_amount * self.contract_value, open_long_price, "long", open_long_amount, profit, self.total_profit, self.total_asset) if cross_below: # 死叉时 if self.position.amount() == 0: price = self.market.open(-1, kline=kline) amount = round(self.total_asset / self.contract_value) info = self.exchange.sellshort(price, amount) push(info) storage.mysql_save_strategy_run_info(self.database, self.datasheet, timestamp, "卖出开空", price, amount, amount * self.contract_value, price, "short", amount, 0, self.total_profit, self.total_asset) if self.position.direction() == 'long': profit = self.position.coverlong_profit(market_type="usd_contract", last=self.market.open(-1, kline=kline)) # 在平多前先计算逻辑盈亏,当前最新成交价为开盘价 self.total_profit += profit self.total_asset += profit cover_long_price = self.market.open(-1, kline=kline) cover_long_amount = self.position.amount() open_short_price = self.market.open(-1, kline=kline) open_short_amount = round(self.total_asset / self.contract_value) info = self.exchange.SELL(cover_long_price, cover_long_amount, open_short_price, open_short_amount) push("此次盈亏:{} 当前总资金:{}".format(profit, self.total_asset) + str(info)) storage.mysql_save_strategy_run_info(self.database, self.datasheet, timestamp, "平多开空", open_short_price, open_short_amount, open_short_amount * self.contract_value, open_short_price, "short", open_short_amount, profit, self.total_profit, self.total_asset) # 止损 if self.position.amount() > 0: if self.position.direction() == 'long' and self.market.low(-1, kline=kline) <= self.position.price() * self.long_stop: # 多单止损 profit = self.position.coverlong_profit(market_type="usd_contract", last=self.position.price() * self.long_stop) # 在平多前先计算逻辑盈亏,当前最新成交价为止损价 self.total_profit += profit self.total_asset += profit price = self.position.price() * self.long_stop amount = self.position.amount() info = self.exchange.sell(price, amount) push("此次盈亏:{} 当前总资金:{}".format(profit, self.total_asset) + str(info)) storage.mysql_save_strategy_run_info(self.database, self.datasheet, timestamp, "卖出止损", price, amount, amount * self.contract_value, 0, "none", 0, profit, self.total_profit, self.total_asset) self.counter += 1 # 计数器加1,控制此根k线上不再下单 if self.position.direction() == 'short' and self.market.high(-1, kline=kline) >= self.position.price() * self.short_stop: # 空头止损 profit = self.position.covershort_profit(market_type="usd_contract", last=self.position.price() * self.short_stop) self.total_profit += profit self.total_asset += profit price = self.position.price() * self.short_stop amount = self.position.amount() info = self.exchange.buytocover(price, amount) push("此次盈亏:{} 当前总资金:{}".format(profit, self.total_asset) + str(info)) storage.mysql_save_strategy_run_info(self.database, self.datasheet, timestamp, "买入止损", price, amount, amount * self.contract_value, 0, "none", 0, profit, self.total_profit, self.total_asset) self.counter += 1 except: logger.info()
def begin_trade(self, kline=None): try: # 异常处理 if self.indicators.CurrentBar( kline=kline) < self.bollinger_lengths: # 如果k线数据不够长就返回 return timestamp = ts_to_datetime_str(utctime_str_to_ts( kline[-1] [0])) if kline else get_localtime() # 非回测模式下时间戳就是当前本地时间 if self.indicators.BarUpdate(kline=kline): self.counter = 0 # k线更新时还原计数器 if self.out_day > 10: # 计算MA的天数最小递减到10。如果达到10,则不再递减。 self.out_day -= 1 # 自适应出场ma的长度参数根据持仓周期递减,持有头寸的时间每多一天,计算MA的天数减1 deviation = float( self.indicators.STDDEV(self.bollinger_lengths, nbdev=2, kline=kline)[-1]) # 标准差 middleband = float( self.indicators.BOLL(self.bollinger_lengths, kline=kline)['middleband'][-1]) # 布林通道中轨 upperband = float(middleband + deviation) # 布林通道上轨 lowerband = float(middleband - deviation) # 布林通道下轨 filter = float( self.market.close(-1, kline=kline) - self.market.close( (self.filter_length * -1) - 1, kline=kline)) # 过滤器:当日收盘价减去30日前的收盘价 ma = float(self.indicators.MA(self.out_day, kline=kline)[-1]) # 自适应移动出场平均线 # 策略主体 # 若k线数据足够长,且满足过滤条件,且当根k线最高价大于等于布林通道上轨,买入开多。 # 开仓处也设置计数器过滤,是为了防止没有启用交易助手的情况下挂单未成交,仓位为零时当根k线一直满足开仓条件,会重复挂单。 if self.indicators.CurrentBar( kline=kline ) >= self.bollinger_lengths and filter > 0 and self.market.high( -1, kline=kline) > upperband and self.counter < 1: if self.position.amount() == 0: # 若当前无持仓 price = upperband # 开多价格为布林通道上轨的值 amount = round(self.total_asset / upperband / self.contract_value) # 合约张数取整 info = self.exchange.buy(price, amount) # 买入开多,并将返回的信息赋值给变量info push(info) # 推送信息 storage.mysql_save_strategy_run_info( self.database, self.datasheet, timestamp, "买入开多", price, amount, amount * price * self.contract_value, price, "long", amount, 0, self.total_profit, self.total_asset) # 将信息保存至数据库 self.counter += 1 # 此策略是在盘中开仓,而在回测时,每根bar只会运行一次,每根bar上的价格不分时间先后,故此处开仓后计数器加1,也就是当根k线不平仓 # 因为实盘时每个ticker进来策略就会运行一次。注意回测和实盘策略运行机制的不同。 self.out_day = self.bollinger_lengths # 开仓后赋值 # 开空 if self.indicators.CurrentBar( kline=kline ) >= self.bollinger_lengths and filter < 0 and self.market.low( -1, kline=kline) < lowerband and self.counter < 1: if self.position.amount() == 0: price = lowerband amount = round(self.total_asset / upperband / self.contract_value) info = self.exchange.sellshort(price, amount) push(info) storage.mysql_save_strategy_run_info( self.database, self.datasheet, timestamp, "卖出开空", price, amount, amount * price * self.contract_value, price, "short", amount, 0, self.total_profit, self.total_asset) self.counter += 1 self.out_day = self.bollinger_lengths # 开仓后赋值 # 如果当前持多,且当根k线最低价小于等于中轨值,触发保护性止损,就平多止损 # 因为回测是一根k线上运行整个策略一次,所以要实现当根k线开仓后当根k线不平仓,需要将self.counter < 1的条件加在平仓的地方 if self.position.direction() == "long" and self.market.low( -1, kline=kline) < middleband and self.counter < 1: profit = self.position.coverlong_profit( last=middleband) # 此处计算平多利润时,传入最新价last为中轨值,也就是触发止损价格的那个值。 self.total_profit += profit # 计算经过本次盈亏后的总利润 self.total_asset += profit # 计算经过本次盈亏后的总资金 price = middleband # 平多价格为中轨值 amount = self.position.amount() # 平仓数量为当前持仓数量 info = self.exchange.sell(price, amount) push(info) self.counter += 1 storage.mysql_save_strategy_run_info( self.database, self.datasheet, timestamp, "卖出止损", price, amount, price * amount * self.contract_value, 0, "none", 0, profit, self.total_profit, self.total_asset) if self.position.direction() == "short" and self.market.high( -1, kline=kline) > middleband and self.counter < 1: profit = self.position.covershort_profit(last=middleband) self.total_profit += profit self.total_asset += profit price = middleband amount = self.position.amount() info = self.exchange.buytocover(price, amount) push(info) self.counter += 1 storage.mysql_save_strategy_run_info( self.database, self.datasheet, timestamp, "买入止损", price, amount, amount * price * self.contract_value, 0, "none", 0, profit, self.total_profit, self.total_asset) # 平多 if self.position.direction( ) == "long" and upperband > ma > self.market.low( -1, kline=kline) and self.counter < 1: profit = self.position.coverlong_profit(last=ma) self.total_profit += profit self.total_asset += profit price = ma # 平仓价格为自适应出场均线的值 amount = self.position.amount() info = self.exchange.sell(price, amount) push(info) self.counter += 1 storage.mysql_save_strategy_run_info( self.database, self.datasheet, timestamp, "卖出平多", price, amount, price * amount * self.contract_value, 0, "none", 0, profit, self.total_profit, self.total_asset) # 平空 if self.position.direction( ) == "short" and lowerband < ma < self.market.high( -1, kline=kline) and self.counter < 1: profit = self.position.covershort_profit(last=ma) self.total_profit += profit self.total_asset += profit price = ma amount = self.position.amount() info = self.exchange.buytocover(price, amount) push(info) self.counter += 1 storage.mysql_save_strategy_run_info( self.database, self.datasheet, timestamp, "买入平空", price, amount, amount * price * self.contract_value, 0, "none", 0, profit, self.total_profit, self.total_asset) except: logger.error()
def begin_trade(self, kline=None): try: if self.indicators.CurrentBar( kline=kline) < self.slow_length: # 如果k线数据不够长就返回 return timestamp = ts_to_datetime_str(utctime_str_to_ts( kline[-1] [0])) if kline else get_localtime() # 非回测模式下时间戳就是当前本地时间 # 计算策略信号 ma = self.indicators.MA(self.fast_length, self.slow_length, kline=kline) fast_ma = ma[0] slow_ma = ma[1] cross_over = fast_ma[-2] >= slow_ma[-2] and fast_ma[-3] < slow_ma[ -3] # 不用当根k线上的ma来计算信号,防止信号闪烁 cross_below = slow_ma[-2] >= fast_ma[-2] and slow_ma[-3] < fast_ma[ -3] if self.indicators.BarUpdate(kline=kline): # 如果k线更新,计数器归零 self.counter = 0 if self.counter < 1: # 按照策略信号开平仓 if cross_over and round( self.position.amount() ) < self.precision: # 金叉时,若当前无持仓,则买入开多并推送下单结果。0.1这个数值根据每个币对的最小交易数量决定 price = float(self.market.open( -1, kline=kline)) # 下单价格=此根k线开盘价 self.hold_price = price # 记录开仓价格 amount = float(self.total_asset / price) # 数量=总资金/价格 info = self.exchange.buy(price, amount) push(info) storage.mysql_save_strategy_run_info( self.database, self.datasheet, timestamp, "买入开多", price, amount, amount * price, price, "long", amount, 0, self.total_profit, self.total_asset) # 将信息保存至数据库 if cross_below and round( self.position.amount(), 1 ) >= self.precision: # 死叉时,如果当前持多就卖出平多。当前持仓数量根据币对的最小交易数量取小数 price = float(self.market.open(-1, kline=kline)) amount = float(self.position.amount()) profit = (price - self.hold_price) * amount # 计算逻辑盈亏 self.total_profit += profit self.total_asset += profit info = self.exchange.sell(price, amount) push(info) self.hold_price = 0 # 平多后记录持仓价格为0 storage.mysql_save_strategy_run_info( self.database, self.datasheet, timestamp, "卖出平多", price, amount, amount * price, 0, "none", 0, profit, self.total_profit, self.total_asset) # 如果当前持多且最低价小于等于持仓均价*止损幅度,触发止损,卖出平多止损 if round(self.position.amount(), 1) >= self.precision and self.market.low( -1, kline=kline) <= self.hold_price * self.long_stop: price = float(self.hold_price * self.long_stop) amount = float(self.position.amount()) profit = (price - self.hold_price) * amount # 计算逻辑盈亏 self.total_profit += profit self.total_asset += profit info = self.exchange.sell(price, amount) push("此次盈亏:{} 当前总资金:{}".format(profit, self.total_asset) + str(info)) self.hold_price = 0 # 平多后记录持仓价格为0 storage.mysql_save_strategy_run_info( self.database, self.datasheet, timestamp, "卖出止损", price, amount, amount * price, 0, "none", 0, profit, self.total_profit, self.total_asset) self.counter += 1 # 计数器加1,控制此根k线上不再下单 except Exception as e: logger.info()
async def subscribe(url, api_key, passphrase, secret_key, channels): while True: try: async with websockets.connect(url) as ws: # login timestamp = str(server_timestamp()) login_str = login_params(timestamp, api_key, passphrase, secret_key) await ws.send(login_str) # time = get_timestamp() # print(time + f"send: {login_str}") res_b = await ws.recv() res = inflate(res_b).decode('utf-8') time = get_timestamp() # print(time + res) # subscribe sub_param = {"op": "subscribe", "args": channels} sub_str = json.dumps(sub_param) await ws.send(sub_str) time = get_timestamp() # print(time + f"send: {sub_str}") while True: try: res_b = await asyncio.wait_for(ws.recv(), timeout=25) except (asyncio.TimeoutError, websockets.exceptions.ConnectionClosed) as e: try: await ws.send('ping') res_b = await ws.recv() time = get_timestamp() res = inflate(res_b).decode('utf-8') # print(time + res) continue except Exception as e: time = get_timestamp() print(time + "连接关闭,正在重连……") print(e) break time = get_timestamp() res = inflate(res_b).decode('utf-8') # print(time + res) # 持仓更新 length = len(res) result = eval(res) if length > 99: if channels[0][0:16] == "futures/position": data = result['data'][0] long_qty = data["long_qty"] short_qty = data["short_qty"] leverage = data["leverage"] long_avg_cost = data["long_avg_cost"] short_avg_cost = data["short_avg_cost"] last = data["last"] instrument_id = data['instrument_id'] info = "【交易提醒】OKEX交割合约持仓更新!合约ID:{} 多头仓位:{} 持多均价:{} 空头仓位:{} 持空均价:{} 最新成交价:{} 杠杆倍数:{}".format( instrument_id, long_qty, long_avg_cost, short_qty, short_avg_cost, last, leverage) if get_localtime()[11:16] != "16:00": push(info) if channels[0][0:13] == "swap/position": data = result['data'][0]['holding'][1] data2 = result['data'][0]['holding'][0] direction2 = data2['side'] amount2 = data2['position'] price2 = data2['avg_cost'] instrument_id = result['data'][0]['instrument_id'] direction = data['side'] amount = data['position'] price = data['avg_cost'] last = data['last'] leverage = data['leverage'] info = "【交易提醒】OKEX永续合约持仓更新!合约ID:{} 多头方向:{} 持多均价:{} 持多数量:{} 空头方向:{} 持空均价:{} 持空数量:{} 最新成交价:{} 杠杆倍数:{}".format( instrument_id, direction2, price2, amount2, direction, price, amount, last, leverage) if get_localtime()[11:16] != "16:00": push(info) if channels[0][0:12] == "spot/account": data = result["data"][0] balance = data["balance"] available = data["available"] currency = data["currency"] hold = data["hold"] info = "【交易提醒】OKEX币币账户更新!币种:{} 余额:{} 冻结:{} 可用:{} ".format( currency, balance, hold, available) if get_localtime()[11:16] != "16:00": push(info) if channels[0][0:19] == "spot/margin_account": symbol = result['data'][0]['instrument_id'] liquidation_price = result['data'][0][ 'liquidation_price'] if len(symbol) == 8: dollar_name = 'currency:{}'.format(symbol[4:8]) coin_name = 'currency:{}'.format(symbol[0:3]) elif len(symbol) == 9: dollar_name = 'currency:{}'.format(symbol[5:9]) coin_name = 'currency:{}'.format(symbol[0:4]) else: dollar_name = 'currency:{}'.format( symbol[6:10]) coin_name = 'currency:{}'.format(symbol[0:5]) dollar_info = result['data'][0][dollar_name] coin_info = result['data'][0][coin_name] dollar_balance = dollar_info['balance'] coin_balance = coin_info['balance'] dollar_available = dollar_info['available'] coin_available = coin_info['available'] dollar_hold = dollar_info['hold'] coin_hold = coin_info['hold'] dollar_borrowed = dollar_info['borrowed'] coin_borrowed = coin_info['borrowed'] info = "【交易提醒】OKEX币币杠杆账户更新!交易对:{} 强平价:{} 计价币:【{} 余额:{} 可用:{} 冻结:{} 已借未还:{}】 交易币:【{} 余额:{} 可用:{} 冻结:{} 已借未还:{}】".format( symbol, liquidation_price, dollar_name, dollar_balance, dollar_available, dollar_hold, dollar_borrowed, coin_name, coin_balance, coin_available, coin_hold, coin_borrowed) if get_localtime()[11:16] != "16:00": push(info) if channels[0][0:15] == "option/position": data = result['data'][0] instrument_id = data['instrument_id'] position = data['position'] avg_cost = data['avg_cost'] option_value = data['option_value'] info = "【交易提醒】OKEX期权合约持仓更新! 合约ID:{} 净持仓数量:{} 开仓平均价:{} 期权市值:{}".format( instrument_id, position, avg_cost, option_value) if get_localtime()[11:16] != "16:00": push(info) except Exception as e: time = get_timestamp() print(time + "连接断开,正在重连……") print(e) continue
def begin_trade(self, kline=None): # 实盘时从交易所实时获取k线数据,回测时传入自定义的kline try: # 如果k线数据不够长就返回 if self.indicators.CurrentBar(kline=kline) < self.fsLength: return # 非回测模式下时间戳就是当前本地时间 timestamp = ts_to_datetime_str(utctime_str_to_ts(kline[-1][0])) if kline else get_localtime() # k线更新时计数器归零 if self.indicators.BarUpdate(kline=kline): self.counter = 0 AvgTR = self.indicators.ATR(self.ATRLength, kline=kline) # 计算真实波幅 N = float(AvgTR[-2]) # N值为前一根bar上的ATR值,需将numpy.float64数据类型转换为float类型,下面的转换同理 Units = int(self.total_asset / self.contract_value / 5) # 每一份头寸大小为总资金的20% """计算短周期唐奇安通道""" # 唐奇安通道上轨,延后1个Bar DonchianHi = float(self.indicators.HIGHEST(self.boLength, kline=kline)[-2]) # 唐奇安通道下轨,延后1个Bar DonchianLo = float(self.indicators.LOWEST(self.boLength, kline=kline)[-2]) """计算长周期唐奇安通道""" # 唐奇安通道上轨,延后1个Bar,长周期 fsDonchianHi = float(self.indicators.HIGHEST(self.fsLength, kline=kline)[-2]) # 唐奇安通道下轨,延后1个Bar,长周期 fsDonchianLo = float(self.indicators.LOWEST(self.fsLength, kline=kline)[-2]) """计算止盈唐奇安通道""" # 离市时判断需要的N周期最低价 ExitLowestPrice = float(self.indicators.LOWEST(self.teLength, kline=kline)[-2]) # 离市时判断需要的N周期最高价 ExitHighestPrice = float(self.indicators.HIGHEST(self.teLength, kline=kline)[-2]) # 当不使用过滤条件,或者使用过滤条件且条件PreBreakoutFailure为True时,短周期开仓 if self.indicators.CurrentBar(kline=kline) >= self.boLength and self.position.amount() == 0 and (self.LastProfitableTradeFilter != 1 or self.PreBreakoutFailure == False) and self.counter < 1: if self.market.high(-1, kline=kline) >= DonchianHi: # 突破了短周期唐奇安通道上轨 price = DonchianHi # 开多价格为短周期唐奇安通道上轨 amount = Units # 开多数量为Units receipt = self.exchange.buy(price, amount) # 开多 push(receipt) # 推送下单结果 self.CurrentEntries += 1 # 记录一次开仓次数 self.PreBreakoutFailure = False # 将标识重置为默认值,根据离场时的盈亏情况再修改 storage.mysql_save_strategy_run_info(self.database, self.datasheet, timestamp, "买入开多", price, amount, amount * self.contract_value, price, "long", amount, 0, self.total_profit, self.total_asset) # 将信息保存至数据库 self.counter += 1 # 计数器加1 if self.market.low(-1, kline=kline) <= DonchianLo: # 突破了短周期唐奇安通道下轨 price = DonchianLo # 开空价格为DonchianLo amount = Units # 开空数量为Units receipt = self.exchange.sellshort(price, amount) # 开空 push(receipt) # 推送下单结果 self.CurrentEntries += 1 # 记录一次开仓次数 self.PreBreakoutFailure = False # 将标识重置为默认值,根据离场时的盈亏情况再修改 storage.mysql_save_strategy_run_info(self.database, self.datasheet, timestamp, "卖出开空", price, amount, amount * self.contract_value, price, "short", amount, 0, self.total_profit, self.total_asset) # 保存信息至数据库 self.counter += 1 # 计数器加1 # 长周期突破开仓,其他逻辑和短周期突破开仓一样。 if self.indicators.CurrentBar(kline=kline) >= self.fsLength and self.position.amount() == 0 and self.counter < 1: if self.market.high(-1, kline=kline) >= fsDonchianHi: # 突破了长周期唐奇安通道上轨 price = fsDonchianHi # 开多价格为长周期唐奇安通道上轨值 amount = Units # 数量为Units receipt = self.exchange.buy(price, amount) # 下单并返回下单结果 push(receipt) # 推送下单结果 self.CurrentEntries += 1 # 记录一次开仓次数 self.PreBreakoutFailure = False # 将标识重置为默认值 storage.mysql_save_strategy_run_info(self.database, self.datasheet, timestamp, "买入开多", price, amount, amount * self.contract_value, price, "long", amount, 0, self.total_profit, self.total_asset) # 将信息保存至数据库 self.counter += 1 # 计数器加1 if self.market.low(-1, kline=kline) <= fsDonchianLo: # 突破长周期唐奇安通道下轨 price = fsDonchianLo # 开空价格为长周期唐奇安通道下轨值 amount = Units # 开空数量为Units receipt = self.exchange.sellshort(price, amount) # 下单并返回下单结果 push(receipt) # 推送下单结果 self.CurrentEntries += 1 # 记录一次开仓次数 self.PreBreakoutFailure = False # 将标识重置为默认值 storage.mysql_save_strategy_run_info(self.database, self.datasheet, timestamp, "卖出开空", price, amount, amount * self.contract_value, price, "short", amount, 0, self.total_profit, self.total_asset) self.counter += 1 # 计数器加1 # 止盈、加仓和止损 if self.position.direction() == "long" and self.counter < 1: # 持多仓的情况。回测时是一根k线上整个策略从上至下运行一次,所以在此处设置计数器过滤 if self.market.low(-1, kline=kline) <= ExitLowestPrice: # 跌破止盈价 profit = self.position.coverlong_profit(last=ExitLowestPrice, market_type="usd_contract") # 平仓前计算利润,传入最新价以及计算盈利的合约类型 self.total_profit += profit # 计算经过本次盈亏后的总利润 self.total_asset += profit # 计算经过本次盈亏后的总资金 price = ExitLowestPrice # 平多价格为ExitLowestPrice amount = self.position.amount() # 数量为当前持仓数量 receipt = self.exchange.sell(price, amount) # 平所有多单仓位 push(receipt) # 推送下单结果 storage.mysql_save_strategy_run_info(self.database, self.datasheet, timestamp, "卖出平多", price, amount, amount * self.contract_value, 0, "none", 0, profit, self.total_profit, self.total_asset) self.counter += 1 # 计数器加1 self.CurrentEntries = 0 # 平仓后将开仓次数还原为0 else: # 加仓指令 '''以最高价为标准,判断是否能加仓,并限制最大加仓次数 如果价格过前次开仓价格1/2N,则直接加仓 ''' while self.market.high(-1, kline=kline) >= (self.position.price() + 0.5 * N) and (self.CurrentEntries <= 4): price = self.position.price() + 0.5 * N # 加仓的开仓价格为持仓价格+0.5 * N amount = Units # 数量为Units storage.mysql_save_strategy_run_info(self.database, self.datasheet, timestamp, "多头加仓", price, amount, amount * self.contract_value, (self.position.price() + price) / 2, "long", self.position.amount() + amount, 0, self.total_profit, self.total_asset) receipt = self.exchange.buy(price, amount) push(receipt) self.CurrentEntries += 1 # 止损指令 if self.market.low(-1, kline=kline) <= (self.position.price() - 2 * N): # 如果回落大于最后下单价格-2n,就止损 profit = self.position.coverlong_profit(last=self.position.price() - 2 * N, market_type="usd_contract") self.total_profit += profit # 计算经过本次盈亏后的总利润 self.total_asset += profit # 计算经过本次盈亏后的总资金 price = self.position.price() - 2 * N amount = self.position.amount() receipt = self.exchange.sell(price, amount) # 全部止损平仓 push(receipt) self.PreBreakoutFailure = True # 记录为突破失败,下次交易将使用长周期开仓 storage.mysql_save_strategy_run_info(self.database, self.datasheet, timestamp, "卖出止损", price, amount, amount * self.contract_value, 0, "none", 0, profit, self.total_profit, self.total_asset) self.counter += 1 self.CurrentEntries = 0 # 平仓后将开仓次数还原为0 elif self.position.direction() == "short" and self.counter < 1: # 持空头的情况,除方向以外,其他逻辑和上面持多仓的一致 if self.market.high(-1, kline=kline) >= ExitHighestPrice: profit = self.position.covershort_profit(last=ExitHighestPrice, market_type="usd_contract") self.total_profit += profit self.total_asset += profit price = ExitHighestPrice amount = self.position.amount() receipt = self.exchange.buytocover(price, amount) push(receipt) storage.mysql_save_strategy_run_info(self.database, self.datasheet, timestamp, "买入平空", price, amount, amount * self.contract_value, 0, "none", 0, profit, self.total_profit, self.total_asset) self.counter += 1 self.CurrentEntries = 0 # 平仓后将开仓次数还原为0 else: while self.market.low(-1, kline=kline) <= (self.position.price() - 0.5 * N) and (self.CurrentEntries <= 4): price = self.position.price() - 0.5 * N amount = Units storage.mysql_save_strategy_run_info(self.database, self.datasheet, timestamp, "空头加仓", price, amount, amount * self.contract_value, (self.position.price() + price) / 2, "short", self.position.amount() + amount, 0, self.total_profit, self.total_asset) receipt = self.exchange.sellshort(self.position.price() - 0.5 * N, Units) push(receipt) self.CurrentEntries += 1 if self.market.high(-1, kline=kline) >= (self.position.price() + 2 * N): profit = self.position.covershort_profit(last=self.position.price() + 2 * N, market_type="usd_contract") self.total_profit += profit self.total_asset += profit price = self.position.price() + 2 * N amount = self.position.amount() receipt = self.exchange.buytocover(price, amount) push(receipt) self.PreBreakoutFailure = True storage.mysql_save_strategy_run_info(self.database, self.datasheet, timestamp, "买入止损", price, amount, amount * self.contract_value, 0, "none", 0, profit, self.total_profit, self.total_asset) self.counter += 1 self.CurrentEntries = 0 # 平仓后将开仓次数还原为0 except: logger.error()