def __init__(self, access_key, secret_key, passphrase, instrument_id, margin_mode=None, leverage=None): """ okex永续合约 :param access_key: :param secret_key: :param passphrase: :param instrument_id: 例如:"BTC-USDT-SWAP", "BTC-USD-SWAP" :param leverage:杠杆倍数,如不填则默认设置20倍杠杆 """ self.__access_key = access_key self.__secret_key = secret_key self.__passphrase = passphrase self.__instrument_id = instrument_id self.__okex_swap = okexswap.SwapAPI(self.__access_key, self.__secret_key, self.__passphrase) self.__leverage = leverage or 20 if margin_mode == "fixed": try: self.__okex_swap.set_leverage(leverage=self.__leverage, instrument_id=self.__instrument_id, side=1) self.__okex_swap.set_leverage(leverage=self.__leverage, instrument_id=self.__instrument_id, side=2) except Exception as e: logger.error("OKEX永续合约设置杠杆倍数失败!请检查账户是否已设置成逐仓模式!错误:{}".format(str(e))) else: try: self.__okex_swap.set_leverage(leverage=self.__leverage, instrument_id=self.__instrument_id, side=3) except Exception as e: logger.error("OKEX永续合约设置杠杆倍数失败!请检查账户是否已设置成全仓模式!错误:{}".format(str(e)))
def __init__(self, access_key, secret_key, passphrase, instrument_id, margin_mode=None, leverage=None): """ okex交割合约,初始化时会自动设置成全仓模式,可以传入参数设定开仓杠杆倍数。 设置合约币种账户模式时,注意:当前有仓位或者有挂单时禁止切换账户模式。 :param access_key: :param secret_key: :param passphrase: :param instrument_id: 例如:"BTC-USD-201225", "BTC-USDT-201225" :param leverage:杠杆倍数,如不填则默认设置为20倍杠杆 """ self.__access_key = access_key self.__secret_key = secret_key self.__passphrase = passphrase self.__instrument_id = instrument_id self.__okex_futures = okexfutures.FutureAPI(self.__access_key, self.__secret_key, self.__passphrase) self.__leverage = leverage or 20 if margin_mode == "fixed": try: self.__okex_futures.set_margin_mode( underlying=self.__instrument_id.split("-")[0] + "-" + self.__instrument_id.split("-")[1], margin_mode="fixed") # 设置账户模式为逐仓模式 self.__okex_futures.set_leverage( leverage=self.__leverage, underlying=self.__instrument_id.split("-")[0] + "-" + self.__instrument_id.split("-")[1], instrument_id=self.__instrument_id, direction="long") # 设置做多方向杠杆倍数 self.__okex_futures.set_leverage( leverage=self.__leverage, underlying=self.__instrument_id.split("-")[0] + "-" + self.__instrument_id.split("-")[1], instrument_id=self.__instrument_id, direction="short") # 设置做空方向杠杆倍数 except Exception as e: logger.error("OKEX交割合约设置逐仓模式失败!错误:{}".format(str(e))) else: try: self.__okex_futures.set_margin_mode( underlying=self.__instrument_id.split("-")[0] + "-" + self.__instrument_id.split("-")[1], margin_mode="crossed") self.__okex_futures.set_leverage( leverage=self.__leverage, underlying=self.__instrument_id.split("-")[0] + "-" + self.__instrument_id.split("-")[1]) # 设置账户模式为全仓模式后再设置杠杆倍数 except Exception as e: logger.error("OKEX交割合约设置全仓模式失败!错误:{}".format(str(e)))
plots.append(fplt.plot(lowerband, legend="LOWERBAND")) else: # every time after we just update the data sources on each plot plots[0].update_data(candlesticks) plots[1].update_data(volumes) plots[2].update_data(upperband) plots[3].update_data(middleband) plots[4].update_data(lowerband) if __name__ == "__main__": try: kline = Kline() plots = [] fplt.foreground = '#FFFFFF' # 前景色 fplt.background = '#333333' # 背景色 fplt.odd_plot_background = '#333333' # 第二层图纸的背景色 fplt.cross_hair_color = "#FFFFFF" # 准星的颜色 ax, ax2 = fplt.create_plot('Realtime kline', init_zoom_periods=100, maximize=False, rows=2) fplt.add_legend("VOLUME", ax2) # 增加"VOLUME"图例 kline.update() fplt.timer_callback( kline.update, 5.0) # update (using synchronous rest call) every N seconds fplt.show() except: logger.error()
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): # 实盘时从交易所实时获取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()