from typing import List from bfxapi import Position from bfxbot.models import Strategy, PositionState, SymbolStatus, Event, EventKind from bfxbot.utils import TAKER_FEE, net_pl_percentage class TrailingStopStrategy(Strategy): BREAK_EVEN_PERC = TAKER_FEE MIN_PROFIT_PERC = TAKER_FEE * 2.5 GOOD_PROFIT_PERC = MIN_PROFIT_PERC * 1.5 MAX_LOSS_PERC = -3.75 OFFER_PERC = 0.01 TRAIL_STOP_PERCENTAGES = { PositionState.MINIMUM_PROFIT: 0.27, PositionState.PROFIT: 0.14 } def position_on_tick(self, position: Position, ss: SymbolStatus) -> (PositionState, List[Event]): events = [] pl_perc = net_pl_percentage(position.profit_loss_percentage, TAKER_FEE) prev = ss.previous_position_w(position.id) if pl_perc > self.GOOD_PROFIT_PERC: state = PositionState.PROFIT elif self.MIN_PROFIT_PERC <= pl_perc < self.GOOD_PROFIT_PERC: state = PositionState.MINIMUM_PROFIT elif 0.0 <= pl_perc < self.MIN_PROFIT_PERC: state = PositionState.BREAK_EVEN elif self.MAX_LOSS_PERC < pl_perc < 0.0: state = PositionState.LOSS else: state = PositionState.CRITICAL if not prev or prev.state == state: return state, events if state ==PositionState.PROFIT: events.append(Event(EventKind.REACHED_GOOD_PROFIT, position.id, ss.current_tick)) elif state == PositionState.MINIMUM_PROFIT: events.append(Event(EventKind.REACHED_MIN_PROFIT, position.id, ss.current_tick)) elif state == PositionState.BREAK_EVEN: events.append(Event(EventKind.REACHED_BREAK_EVEN, position.id, ss.current_tick)) elif state== PositionState.LOSS: events.append(Event(EventKind.REACHED_LOSS, position.id, ss.current_tick)) else: events.append(Event(EventKind.REACHED_MAX_LOSS, position.id, ss.current_tick)) events.append(Event(EventKind.CLOSE_POSITION, position.id, ss.current_tick)) return state, events