tailwind #9
@ -65,7 +65,7 @@ class BfxBot:
|
||||
|
||||
# emitting new tick event
|
||||
## 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]:
|
||||
pw: Optional[PositionWrapper] = self.__position_wrapper_from_id(position_id)
|
||||
|
@ -120,6 +120,10 @@ class SymbolStatus:
|
||||
self.current_tick: int = 1
|
||||
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):
|
||||
if self.strategy:
|
||||
self.strategy.order_on_new_tick(order, self)
|
||||
@ -162,10 +166,6 @@ class SymbolStatus:
|
||||
def set_tick_price(self, 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):
|
||||
if not self.strategy:
|
||||
return
|
||||
@ -185,7 +185,7 @@ class SymbolStatus:
|
||||
for e in events:
|
||||
if not isinstance(e, Event):
|
||||
raise ValueError
|
||||
await self.__add_event__(e)
|
||||
await self.add_event__(e)
|
||||
|
||||
return pw
|
||||
|
||||
@ -239,15 +239,15 @@ class EventHandler:
|
||||
if state in self.state_handlers:
|
||||
for h in self.state_handlers[state]:
|
||||
if inspect.iscoroutinefunction(h):
|
||||
await h(status)
|
||||
await h(pw, status)
|
||||
else:
|
||||
h(status)
|
||||
h(pw, status)
|
||||
|
||||
for h in self.any_state:
|
||||
if inspect.iscoroutinefunction(h):
|
||||
await h(status)
|
||||
await h(pw, status)
|
||||
else:
|
||||
h(status)
|
||||
h(pw, status)
|
||||
|
||||
def on_event(self, kind: EventKind):
|
||||
value = kind.value
|
||||
|
16
main.py
16
main.py
@ -12,7 +12,7 @@ from flask_socketio import SocketIO
|
||||
|
||||
from bfxbot import BfxBot
|
||||
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 strategy import TrailingStopStrategy
|
||||
|
||||
@ -35,7 +35,8 @@ app = Flask(__name__)
|
||||
socketio = SocketIO(app, async_mode="threading")
|
||||
bot = BfxBot(api_key=API_KEY, api_secret=API_SECRET,
|
||||
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)
|
||||
|
||||
# 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))
|
||||
|
||||
|
||||
@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)
|
||||
def on_new_tick(event: Event, status: SymbolStatus):
|
||||
tick = event.tick
|
||||
@ -106,6 +117,7 @@ def on_new_tick(event: Event, status: SymbolStatus):
|
||||
|
||||
@btc_eh.on_any_event()
|
||||
def on_any_event(event: Event, _):
|
||||
await strategy
|
||||
socketio.emit("new_event", {
|
||||
"tick": event.tick,
|
||||
"kind": event.kind.name
|
||||
|
21
strategy.py
21
strategy.py
@ -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))
|
||||
|
||||
def __init__(self):
|
||||
self.stop_percentage: float = None
|
||||
|
||||
def position_on_new_tick(self, position: Position, ss: SymbolStatus) -> (PositionState, List[Event]):
|
||||
events = []
|
||||
|
||||
@ -88,3 +91,21 @@ class TrailingStopStrategy(Strategy):
|
||||
events.append(Event(EventKind.CLOSE_POSITION, ss.current_tick, event_metadata))
|
||||
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user