예제 #1
0
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
예제 #2
0
    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()
예제 #4
0
 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()
예제 #5
0
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
예제 #6
0
 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()