Пример #1
0
class HighFrequencyStrategy(CtaTemplate):
    """
    网格的高频策略,挂上下买卖单,等待成交,然后通过不断加仓降低均价

    免责声明: 本策略仅供测试参考,本人不负有任何责任。使用前请熟悉代码。测试其中的bugs, 请清楚里面的功能后在使用。
    币安邀请链接: https://www.binancezh.pro/cn/futures/ref/51bitquant
    合约邀请码:51bitquant
    """
    author = "51bitquant"

    grid_step = 1.0
    stop_multiplier = 15.0
    trading_size = 1.0
    max_pos = 15.0  # 最大的持仓数量.
    stop_mins = 15.0  # 出现亏损是,暂停多长时间.

    # 变量.
    avg_price = 0.0
    current_pos = 0.0

    parameters = [
        "grid_step", "stop_multiplier", "trading_size", "max_pos", "stop_mins"
    ]
    variables = ["avg_price", "current_pos"]

    def __init__(self, cta_engine: CtaEngine, strategy_name, vt_symbol,
                 setting):
        """"""
        super().__init__(cta_engine, strategy_name, vt_symbol, setting)

        self.position = GridPositionCalculator(grid_step=self.grid_step)
        self.avg_price = self.position.avg_price
        self.current_pos = self.position.pos

        # orders
        self.long_orders = []
        self.short_orders = []

        self.stop_orders = []
        self.profit_orders = []

        self.timer_count = 0
        self.stop_loss_interval = 0
        self.trigger_stop_loss = False
        self.cancel_order_interval = 0

        self.tick: TickData = None
        self.last_filled_order: OrderData = None

    def on_init(self):
        """
        Callback when strategy is inited.
        """
        self.write_log("策略初始化")

    def on_start(self):
        """
        Callback when strategy is started.
        """
        self.write_log("策略启动")
        self.cta_engine.event_engine.register(EVENT_TIMER,
                                              self.process_timer_event)

    def on_stop(self):
        """
        Callback when strategy is stopped.
        """
        self.write_log("策略停止")
        self.cta_engine.event_engine.unregister(EVENT_TIMER,
                                                self.process_timer_event)

    def process_timer_event(self, event: Event):

        self.timer_count += 1

        if self.timer_count >= 60:
            self.timer_count = 0

            # 撤销止损单子.
            for vt_id in self.stop_orders:
                self.cancel_order(vt_id)

        if self.trigger_stop_loss:
            self.stop_loss_interval += 1

        # 止盈的条件, 可以放到tick里面,也可以放到定时器这里.
        if abs(self.position.pos) > 0 and self.tick:

            if self.position.pos > 0 and len(self.profit_orders) == 0:

                price = self.position.avg_price + self.grid_step
                price = max(price, self.tick.ask_price_1 * (1 + 0.0001))

                vts = self.sell(price, abs(self.position.pos))
                self.profit_orders.extend(vts)
                print(f"多头重新下止盈单子: {vts}@{price}")

            elif self.position.pos < 0 and len(self.profit_orders) == 0:

                price = self.position.avg_price - self.grid_step
                price = min(price, self.tick.bid_price_1 * (1 - 0.0001))

                vts = self.cover(price, abs(self.position.pos))
                self.profit_orders.extend(vts)
                print(f"空头重新下止盈单子: {vts}@{price}")

        self.cancel_order_interval += 1

        if self.cancel_order_interval >= 15:

            self.cancel_order_interval = 0

            if abs(self.position.pos) < self.trading_size and (len(
                    self.long_orders) == 0 or len(self.short_orders) == 0):
                self.cancel_all()
                print("当前没有仓位,多空单子不对等,需要重新开始. 先撤销所有订单.")

            elif 0 < abs(
                    self.position.pos) < (self.max_pos * self.trading_size):
                if self.position.pos > 0 and len(
                        self.long_orders) == 0 and self.last_filled_order:

                    step = self.get_step()
                    price = self.last_filled_order.price - self.grid_step * step
                    price = min(price, self.tick.bid_price_1 * (1 - 0.0001))
                    ids = self.buy(price, self.trading_size)
                    self.long_orders.extend(ids)

                elif self.position.pos < 0 and len(
                        self.short_orders) == 0 and self.last_filled_order:

                    step = self.get_step()
                    price = self.last_filled_order.price + self.grid_step * step
                    price = max(price, self.tick.ask_price_1 * (1 + 0.0001))

                    ids = self.short(price, self.trading_size)
                    self.short_orders.extend(ids)

    def on_tick(self, tick: TickData):
        """
        Callback of new tick data update.
        """
        self.tick = tick

        if not self.trading:
            return

        if tick.bid_price_1 <= 0 or tick.ask_price_1 <= 0:
            self.write_log(
                f"tick价格异常: bid1: {tick.bid_price_1}, ask1: {tick.ask_price_1}"
            )
            return

        if abs(self.position.pos) < self.trading_size:  # 仓位为零的情况.

            if len(self.long_orders) == 0 and len(self.short_orders) == 0:

                if self.trigger_stop_loss:
                    # 记录设置过的止损条件.
                    if self.stop_loss_interval < self.stop_mins * 60:  # 休息15分钟.
                        return
                    else:
                        self.trigger_stop_loss = False
                        self.stop_loss_interval = 0

                buy_price = tick.bid_price_1 - self.grid_step / 2
                sell_price = tick.bid_price_1 + self.grid_step / 2

                long_ids = self.buy(buy_price, self.trading_size)
                short_ids = self.short(sell_price, self.trading_size)

                self.long_orders.extend(long_ids)
                self.short_orders.extend(short_ids)

                print(
                    f"开始新的一轮状态: long_orders: {long_ids}@{buy_price}, short_orders:{short_ids}@{sell_price}"
                )

        if abs(self.position.pos) >= (self.max_pos *
                                      self.trading_size) and len(
                                          self.stop_orders) == 0:

            if self.position.pos > 0 and tick.ask_price_1 < self.position.avg_price - self.stop_multiplier * self.grid_step:
                vt_ids = self.sell(tick.ask_price_1, abs(self.position.pos))
                stop_price = self.position.avg_price - self.stop_multiplier * self.grid_step
                self.stop_orders.extend(vt_ids)
                self.trigger_stop_loss = True
                print(
                    f"下多头止损单: stop_price: {stop_price}stop@{tick.ask_price_1}")

            elif self.position.pos < 0 and tick.bid_price_1 > self.position.avg_price + self.stop_multiplier * self.grid_step:

                stop_price = self.position.avg_price + self.stop_multiplier * self.grid_step
                vt_ids = self.cover(tick.bid_price_1, abs(self.position.pos))
                self.stop_orders.extend(vt_ids)
                self.trigger_stop_loss = True
                print(
                    f"下空头止损单: stop_price: {stop_price}stop@{tick.bid_price_1}")

    def on_bar(self, bar: BarData):
        """
        Callback of new bar data update.
        """
        pass

    def get_step(self) -> int:

        pos = abs(self.position.pos)

        if pos < 3 * self.trading_size:
            return 1

        elif pos < 5 * self.trading_size:
            return 2

        elif pos < 8 * self.trading_size:
            return 3

        elif pos < 11 * self.trading_size:
            return 5

        elif pos < 13 * self.trading_size:
            return 6

        return 8

    def on_order(self, order: OrderData):
        """
        Callback of new order data update.
        """
        self.position.update_position(order)
        self.current_pos = self.position.pos
        self.avg_price = self.position.avg_price

        if order.vt_orderid in self.long_orders:
            if order.status == Status.ALLTRADED:
                self.long_orders.remove(order.vt_orderid)

                print("多头成交,撤销空头订单和止盈订单")
                for vt_id in (self.short_orders + self.profit_orders):
                    self.cancel_order(vt_id)

                self.last_filled_order = order

                if self.position.pos > 0:
                    if abs(self.position.pos
                           ) < self.trading_size * self.max_pos:
                        if not self.tick:
                            return

                        step = self.get_step()
                        price = order.price - self.grid_step * step
                        price = min(price,
                                    self.tick.bid_price_1 * (1 - 0.0001))
                        ids = self.buy(price, self.trading_size)
                        self.long_orders.extend(ids)
                        print(f"多头仓位继续下多头订单: {ids}@{price}")

            elif order.status in [Status.REJECTED, Status.CANCELLED]:
                self.long_orders.remove(order.vt_orderid)

        elif order.vt_orderid in self.short_orders:
            if order.status == Status.ALLTRADED:
                self.short_orders.remove(order.vt_orderid)

                print("空头成交,撤销多头订单和止盈订单")
                for vt_id in (self.long_orders + self.profit_orders):
                    self.cancel_order(vt_id)

                self.last_filled_order = order

                if self.position.pos < 0:
                    if abs(self.position.pos
                           ) < self.trading_size * self.max_pos:
                        if not self.tick:
                            return

                        step = self.get_step()
                        price = order.price + self.grid_step * step
                        price = max(price,
                                    self.tick.ask_price_1 * (1 + 0.0001))

                        ids = self.short(price, self.trading_size)
                        self.short_orders.extend(ids)

                        print(f"空头仓位继续下空头订单: {ids}@{price}")

            elif order.status in [Status.REJECTED, Status.CANCELLED]:
                self.short_orders.remove(order.vt_orderid)  # remove orderid

        elif order.vt_orderid in self.stop_orders:
            if not order.is_active():
                self.stop_orders.remove(order.vt_orderid)

        elif order.vt_orderid in self.profit_orders:
            if not order.is_active():
                self.profit_orders.remove(order.vt_orderid)

        self.put_event()

    def on_trade(self, trade: TradeData):
        """
        Callback of new trade data update.
        """
        self.put_event()

    def on_stop_order(self, stop_order: StopOrder):
        """
        Callback of stop order update.
        """
        pass
class SpotProfitGridStrategy(CtaTemplate):
    """
    币安现货网格策略,添加止盈止损的功能.
    该策略没有止盈止损功能,一直在成交的上下方进行高卖低卖操作, 达到最大的单子数量的时候,会计算仓位均价,然后进行平仓操作.
    免责声明: 本策略仅供测试参考,本人不负有任何责任。使用前请熟悉代码。测试其中的bugs, 请清楚里面的功能后再使用。
    币安邀请链接: https://www.binancezh.pro/cn/futures/ref/51bitquant
    合约邀请码:51bitquant
    """
    author = "51bitquant"

    grid_step = 2.0  # 网格间隙.  2usdt, 1.8USDT
    profit_step = 2.0  # 获利的间隔.
    trading_size = 1.0  # 每次下单的头寸.
    max_pos = 100  # 最大的头寸数, 表示不会触发止损的条件.
    profit_orders_counts = 5 # 出现单边吃单太多的时候会考虑止盈.
    trailing_stop_multiplier = 2.0
    stop_minutes = 360.0  # sleep for six hour

    # 变量
    avg_price = 0.0
    current_pos = 0.0

    parameters = ["grid_step", "profit_step", "trading_size", "max_pos", "profit_orders_counts",
                  "trailing_stop_multiplier", "stop_minutes"]

    variables = ["avg_price", "current_pos"]

    def __init__(self, cta_engine: CtaEngine, strategy_name, vt_symbol, setting):
        """"""
        super().__init__(cta_engine, strategy_name, vt_symbol, setting)

        self.position_calculator = GridPositionCalculator(grid_step=self.grid_step)  # 计算仓位用的对象
        self.current_pos = self.position_calculator.pos
        self.avg_price = self.position_calculator.avg_price

        self.normal_timer_interval = 0
        self.profit_order_interval = 0
        self.stop_order_interval = 0
        self.stop_strategy_interval = 0

        self.long_orders = []  # 所有的long orders.
        self.short_orders = []  # 所有的short orders.
        self.profit_orders = []  # profit orders.
        self.stop_orders = []  # stop orders.

        self.trigger_stop_loss = False  # 是否触发止损。

        self.last_filled_order: Union[OrderData, None] = None

        self.tick: Union[TickData,None] = None

    def on_init(self):
        """
        Callback when strategy is inited.
        """
        self.write_log("策略初始化")

    def on_start(self):
        """
        Callback when strategy is started.
        """
        self.write_log("策略启动")
        self.cta_engine.event_engine.register(EVENT_TIMER, self.process_timer_event)

        self.position_calculator = GridPositionCalculator(
            grid_step=self.grid_step)  # 计算仓位用的对象

        self.avg_price = self.position_calculator.avg_price
        self.current_pos = self.position_calculator.pos

    def on_stop(self):
        """
        Callback when strategy is stopped.
        """
        self.write_log("策略停止")
        self.cta_engine.event_engine.unregister(EVENT_TIMER, self.process_timer_event)

    def process_timer_event(self, event: Event):

        if self.tick is None:
            return

        if self.trigger_stop_loss:
            self.stop_strategy_interval += 1  # 如果触发了止损,然后就会开始计时.

        self.normal_timer_interval += 1

        if self.normal_timer_interval >= NORMAL_TIMER_INTERVAL:
            self.normal_timer_interval = 0

            # 仓位为零的时候
            if abs(self.position_calculator.pos) < self.trading_size:
                if len(self.long_orders) == 0 and len(self.short_orders) == 0:
                    if self.trigger_stop_loss:
                        # 如果触发了止损就需要休息一段时间.
                        if self.stop_order_interval < self.stop_minutes * 60:
                            return
                        else:
                            self.stop_order_interval = 0
                            self.trigger_stop_loss = False

                    buy_price = self.tick.bid_price_1 - self.grid_step / 2
                    sell_price = self.tick.bid_price_1 + self.grid_step / 2
                    long_ids = self.buy(buy_price, self.trading_size)
                    short_ids = self.sell(sell_price, self.trading_size) # 现货。 ETH/BUSD,  BTCBUSD

                    self.long_orders.extend(long_ids)
                    self.short_orders.extend(short_ids)

                    print(
                        f"开启网格交易,双边下单:LONG: { self.long_orders}: {buy_price}, SHORT: { self.short_orders}:{sell_price}")

                elif len(self.long_orders) == 0 or len(self.short_orders) == 0:
                    print(f"仓位为零且单边网格没有订单, 先撤掉所有订单")
                    self.cancel_all()

            elif abs(self.position_calculator.pos) >= self.trading_size:

                if len(self.long_orders) > 0 and len(self.short_orders) > 0:
                    return

                if self.last_filled_order:
                    price = self.last_filled_order.price
                else:
                    price = self.tick.bid_price_1

                buy_step = self.get_step()
                sell_step = self.get_step()

                buy_price = price - buy_step * self.grid_step
                sell_price = price + sell_step * self.grid_step

                buy_price = min(self.tick.bid_price_1, buy_price)
                sell_price = max(self.tick.ask_price_1, sell_price)
                long_ids = self.buy(buy_price, self.trading_size)
                short_ids = self.sell(sell_price, self.trading_size)

                self.long_orders.extend(long_ids)
                self.short_orders.extend(short_ids)
                print(f"仓位不为零, 根据上个订单下双边网格.LONG:{long_ids}:{buy_price}, SHORT: {short_ids}:{sell_price}")

        self.profit_order_interval += 1

        if self.profit_order_interval >= PROFIT_TIMER_INTERVAL:
            self.profit_order_interval = 0

            if abs(self.position_calculator.pos) >= self.profit_orders_counts * self.trading_size and len(
                    self.profit_orders) == 0:
                print(f"单边网格出现超过{self.profit_orders_counts}个订单以上,头寸为:{self.position_calculator.pos}, 考虑设置止盈的情况")

                if self.position_calculator.pos > 0:
                    price = max(self.tick.ask_price_1 * (1 + 0.0001),
                                self.position_calculator.avg_price + self.profit_step)
                    order_ids = self.sell(price, abs(self.position_calculator.pos))
                    self.profit_orders.extend(order_ids)
                    print(f"多头止盈情况: {self.position_calculator.pos}@{price}")
                elif self.position_calculator.pos < 0:
                    price = min(self.tick.bid_price_1 * (1 - 0.0001),
                                self.position_calculator.avg_price - self.profit_step)
                    order_ids = self.buy(price, abs(self.position_calculator.pos))
                    self.profit_orders.extend(order_ids)
                    print(f"空头止盈情况: {self.position_calculator.pos}@{price}")

        self.stop_order_interval += 1
        if self.stop_order_interval >= STOP_TIMER_INTERVAL:
            self.stop_order_interval = 0

            for vt_id in self.stop_orders:
                self.cancel_order(vt_id)

            # 如果仓位达到最大值的时候.
            if abs(self.position_calculator.pos) >= self.max_pos * self.trading_size:

                if self.last_filled_order:
                    if self.position_calculator.pos > 0:
                        if self.tick.bid_price_1 < self.last_filled_order.price - self.trailing_stop_multiplier * self.grid_step:
                            vt_ids = self.sell(self.tick.bid_price_1, abs(self.position_calculator.pos))
                            self.stop_orders.extend(vt_ids)

                    elif self.position_calculator.pos < 0:
                        if self.tick.ask_price_1 > self.last_filled_order.price + self.trailing_stop_multiplier * self.grid_step:
                            vt_ids = self.buy(self.tick.ask_price_1, abs(self.position_calculator.pos))
                            self.stop_orders.extend(vt_ids)

                else:
                    if self.position_calculator.pos > 0:
                        if self.tick.bid_price_1 < self.position_calculator.avg_price - self.max_pos * self.grid_step:
                            vt_ids = self.sell(self.tick.bid_price_1, abs(self.position_calculator.pos))
                            self.stop_orders.extend(vt_ids)

                    elif self.position_calculator.pos < 0:
                        if self.tick.ask_price_1 > self.position_calculator.avg_price + self.max_pos * self.grid_step:
                            vt_ids = self.buy(self.tick.ask_price_1, abs(self.position_calculator.pos))
                            self.stop_orders.extend(vt_ids)

    def on_tick(self, tick: TickData):
        """
        Callback of new tick data update.
        """
        self.tick = tick

    def on_bar(self, bar: BarData):
        """
        Callback of new bar data update.
        """
        pass

    def on_order(self, order: OrderData):
        """
        Callback of new order data update.
        """
        self.position_calculator.update_position(order)

        self.current_pos = self.position_calculator.pos
        self.avg_price = self.position_calculator.avg_price

        if order.status == Status.ALLTRADED:
            if order.vt_orderid in (self.long_orders + self.short_orders):

                if order.vt_orderid in self.long_orders:
                    self.long_orders.remove(order.vt_orderid)

                if order.vt_orderid in self.short_orders:
                    self.short_orders.remove(order.vt_orderid)

                self.cancel_all()
                print(f"订单买卖单完全成交, 先撤销所有订单")

                self.last_filled_order = order

                if abs(self.position_calculator.pos) < self.trading_size:
                    print("仓位为零, 需要重新开始.")
                    return

                # tick 存在且仓位数量还没有达到设置的最大值.
                if self.tick and abs(self.position_calculator.pos) < self.max_pos * self.trading_size:
                    buy_step = self.get_step()
                    sell_step = self.get_step()

                    # 解决步长的问题.
                    buy_price = order.price - buy_step * self.grid_step
                    sell_price = order.price + sell_step * self.grid_step

                    buy_price = min(self.tick.bid_price_1 * (1 - 0.0001), buy_price)
                    sell_price = max(self.tick.ask_price_1 * (1 + 0.0001), sell_price)  # BUSD

                    long_ids = self.buy(buy_price, self.trading_size)
                    short_ids = self.sell(sell_price, self.trading_size)

                    self.long_orders.extend(long_ids)
                    self.short_orders.extend(short_ids)

                    print(
                        f"订单完全成交, 分别下双边网格: LONG: {self.long_orders}:{buy_price}, SHORT: {self.short_orders}:{sell_price}")

            elif order.vt_orderid in self.profit_orders:
                self.profit_orders.remove(order.vt_orderid)
                if abs(self.position_calculator.pos) < self.trading_size:
                    self.cancel_all()
                    print(f"止盈单子成交,且仓位为零, 先撤销所有订单,然后重新开始")

            elif order.vt_orderid in self.stop_orders:
                self.stop_orders.remove(order.vt_orderid)
                if abs(self.position_calculator.pos) < self.trading_size:
                    self.trigger_stop_loss = True
                    self.cancel_all()

                    print("止损单子成交,且仓位为零, 先撤销所有订单,然后重新开始")

        if not order.is_active():
            if order.vt_orderid in self.long_orders:
                self.long_orders.remove(order.vt_orderid)

            elif order.vt_orderid in self.short_orders:
                self.short_orders.remove(order.vt_orderid)

            elif order.vt_orderid in self.profit_orders:
                self.profit_orders.remove(order.vt_orderid)

            elif order.vt_orderid in self.stop_orders:
                self.stop_orders.remove(order.vt_orderid)

        self.put_event()

    def on_trade(self, trade: TradeData):
        """
        Callback of new trade data update.
        """
        self.put_event()

    def on_stop_order(self, stop_order: StopOrder):
        """
        Callback of stop order update.
        """
        pass

    def get_step(self) -> int:
        return 1

        # 1,2,3,4,5
        # 1 , 1.2, 1,4