added trailing stop

This commit is contained in:
Giulio De Pasquale 2020-12-16 13:36:20 +00:00
parent 912c4db2e2
commit c19530badb
4 changed files with 45 additions and 12 deletions

View File

@ -65,7 +65,7 @@ class BfxBot:
# emitting new tick event # emitting new tick event
## TODO: handle _on_new_tick() from Strategy ## TODO: handle _on_new_tick() from Strategy
await self.__status[symbol].__add_event__(Event(EventKind.NEW_TICK, self.__ticker.current_tick)) await self.__status[symbol].add_event(Event(EventKind.NEW_TICK, self.__ticker.current_tick))
async def best_position_closing_price(self, position_id: int) -> Optional[float]: async def best_position_closing_price(self, position_id: int) -> Optional[float]:
pw: Optional[PositionWrapper] = self.__position_wrapper_from_id(position_id) pw: Optional[PositionWrapper] = self.__position_wrapper_from_id(position_id)

View File

@ -120,6 +120,10 @@ class SymbolStatus:
self.current_tick: int = 1 self.current_tick: int = 1
self.strategy: Strategy = strategy self.strategy: Strategy = strategy
async def add_event(self, event: Event):
self.events.append(event)
await self.eh.call_event(self, event)
def add_order(self, order: Order): def add_order(self, order: Order):
if self.strategy: if self.strategy:
self.strategy.order_on_new_tick(order, self) self.strategy.order_on_new_tick(order, self)
@ -162,10 +166,6 @@ class SymbolStatus:
def set_tick_price(self, tick, price): def set_tick_price(self, tick, price):
self.prices[tick] = price self.prices[tick] = price
async def __add_event__(self, event: Event):
self.events.append(event)
await self.eh.call_event(self, event)
async def __apply_strategy_to_position__(self, position: Position): async def __apply_strategy_to_position__(self, position: Position):
if not self.strategy: if not self.strategy:
return return
@ -185,7 +185,7 @@ class SymbolStatus:
for e in events: for e in events:
if not isinstance(e, Event): if not isinstance(e, Event):
raise ValueError raise ValueError
await self.__add_event__(e) await self.add_event__(e)
return pw return pw
@ -239,15 +239,15 @@ class EventHandler:
if state in self.state_handlers: if state in self.state_handlers:
for h in self.state_handlers[state]: for h in self.state_handlers[state]:
if inspect.iscoroutinefunction(h): if inspect.iscoroutinefunction(h):
await h(status) await h(pw, status)
else: else:
h(status) h(pw, status)
for h in self.any_state: for h in self.any_state:
if inspect.iscoroutinefunction(h): if inspect.iscoroutinefunction(h):
await h(status) await h(pw, status)
else: else:
h(status) h(pw, status)
def on_event(self, kind: EventKind): def on_event(self, kind: EventKind):
value = kind.value value = kind.value

16
main.py
View File

@ -12,7 +12,7 @@ from flask_socketio import SocketIO
from bfxbot import BfxBot from bfxbot import BfxBot
from bfxbot.currency import Symbol from bfxbot.currency import Symbol
from bfxbot.models import PositionWrapper, SymbolStatus, Event, EventKind from bfxbot.models import PositionWrapper, SymbolStatus, Event, EventKind, PositionState
from bfxbot.utils import pos_to_json from bfxbot.utils import pos_to_json
from strategy import TrailingStopStrategy from strategy import TrailingStopStrategy
@ -35,7 +35,8 @@ app = Flask(__name__)
socketio = SocketIO(app, async_mode="threading") socketio = SocketIO(app, async_mode="threading")
bot = BfxBot(api_key=API_KEY, api_secret=API_SECRET, bot = BfxBot(api_key=API_KEY, api_secret=API_SECRET,
symbols=[Symbol.BTC], tick_duration=20) symbols=[Symbol.BTC], tick_duration=20)
bot.set_strategy(Symbol.BTC, TrailingStopStrategy()) strategy = TrailingStopStrategy()
bot.set_strategy(Symbol.BTC, strategy)
btc_eh = bot.symbol_event_handler(Symbol.BTC) btc_eh = bot.symbol_event_handler(Symbol.BTC)
# initializing and starting bot on other thread # initializing and starting bot on other thread
@ -92,6 +93,16 @@ def on_close_position(event: Event, _):
loop.run_until_complete(bot.close_position(event.metadata.position_id)) loop.run_until_complete(bot.close_position(event.metadata.position_id))
@btc_eh.on_position_state(PositionState.PROFIT)
async def on_state_min_profit(pw: PositionWrapper, ss: SymbolStatus):
await strategy.update_stop_percentage(pw, ss)
@btc_eh.on_position_state(PositionState.MINIMUM_PROFIT)
async def on_state_min_profit(pw: PositionWrapper, ss: SymbolStatus):
await strategy.update_stop_percentage(pw, ss)
@btc_eh.on_event(EventKind.NEW_TICK) @btc_eh.on_event(EventKind.NEW_TICK)
def on_new_tick(event: Event, status: SymbolStatus): def on_new_tick(event: Event, status: SymbolStatus):
tick = event.tick tick = event.tick
@ -106,6 +117,7 @@ def on_new_tick(event: Event, status: SymbolStatus):
@btc_eh.on_any_event() @btc_eh.on_any_event()
def on_any_event(event: Event, _): def on_any_event(event: Event, _):
await strategy
socketio.emit("new_event", { socketio.emit("new_event", {
"tick": event.tick, "tick": event.tick,
"kind": event.kind.name "kind": event.kind.name

View File

@ -51,6 +51,9 @@ class TrailingStopStrategy(Strategy):
TRAILING_STOP = SquaredTrailingStop(Point(MIN_PROFIT_PERC, MIN_PROFIT_PERC / 3 * 2), Point(GOOD_PROFIT_PERC, 0.1)) TRAILING_STOP = SquaredTrailingStop(Point(MIN_PROFIT_PERC, MIN_PROFIT_PERC / 3 * 2), Point(GOOD_PROFIT_PERC, 0.1))
def __init__(self):
self.stop_percentage: float = None
def position_on_new_tick(self, position: Position, ss: SymbolStatus) -> (PositionState, List[Event]): def position_on_new_tick(self, position: Position, ss: SymbolStatus) -> (PositionState, List[Event]):
events = [] events = []
@ -88,3 +91,21 @@ class TrailingStopStrategy(Strategy):
events.append(Event(EventKind.CLOSE_POSITION, ss.current_tick, event_metadata)) events.append(Event(EventKind.CLOSE_POSITION, ss.current_tick, event_metadata))
return pw, events return pw, events
async def update_stop_percentage(self, pw: PositionWrapper, ss: SymbolStatus):
current_pl_perc = pw.net_profit_loss_percentage()
# set stop percentage for first time
if not self.stop_percentage:
await ss.add_event(Event(EventKind.TRAILING_STOP_SET, ss.current_tick))
self.stop_percentage = current_pl_perc - self.TRAILING_STOP.y(current_pl_perc)
return
# moving trailing stop
if current_pl_perc - self.TRAILING_STOP.y(pw.net_profit_loss_percentage()) > self.stop_percentage:
await ss.add_event(Event(EventKind.TRAILING_STOP_MOVED, ss.current_tick))
self.stop_percentage = current_pl_perc - self.TRAILING_STOP.y(current_pl_perc)
return