moved trailing stop strategy to separate file. added function to calculate trailing stop

This commit is contained in:
Giulio De Pasquale 2020-12-07 12:27:09 +00:00
parent 5d5fbc91e1
commit 6c7f0989a6
2 changed files with 106 additions and 71 deletions

82
main.py
View File

@ -485,92 +485,34 @@
# if __name__ == "__main__":
# asyncio.run(Screen.wrapper(main))
import asyncio
from typing import List
import os
from bfxapi import Position
import dotenv
from bfxbot import BfxBot
import dotenv
import os
import bfxapi
from bfxbot.currency import Symbol
from bfxbot.models import Strategy, SymbolStatus, PositionState, Event, EventKind
from bfxbot.utils import TAKER_FEE, net_pl_percentage
from bfxbot.models import PositionState
from strategy import TrailingStopStrategy
dotenv.load_dotenv()
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
async def main():
API_KEY = os.getenv("API_KEY")
API_SECRET = os.getenv("API_SECRET")
if API_KEY == None:
print("API_KEY is not set! Set the var in the .env file.")
return
if API_SECRET == None:
print("API_SECRET is not set! Set the var in the .env file.")
return
bot = BfxBot(api_key=API_KEY, api_secret=API_SECRET)
strategy = TrailingStopStrategy()
bot.set_strategy(Symbol.BTC, strategy)
await bot.start()
eh = bot.event_handler(Symbol.BTC)
@eh.on_state(PositionState.PROFIT)
def on_min_profit(ss, pw):
print("Minimum profit!")
async def main():
await bot.start()
while True:
print("WAITING...")
await bot.update()
if __name__ == '__main__':
asyncio.run(main())

93
strategy.py Normal file
View File

@ -0,0 +1,93 @@
from typing import List
import sympy.abc
from sympy import Point, solve
from bfxbot.models import Strategy, PositionState, SymbolStatus, Event, EventKind
from bfxbot.utils import TAKER_FEE, net_pl_percentage
class Position(object):
def __init__(self):
self.id = None
self.profit_loss_percentage = None
pass
class SquaredTrailingStop:
def __init__(self, p_min: Point, p_max: Point):
a = sympy.abc.a
b = sympy.abc.b
c = sympy.abc.c
self.p_min = p_min
self.p_max = p_max
e1 = 2 * a * (p_max.x + b)
e2 = a * (p_min.x + b)**2 + c - p_min.y
e3 = a * (p_max.x + b)**2 + c - p_max.y
s = solve([e1, e2, e3])[0]
self.a, self.b, self.c = s[a], s[b], s[c]
def y(self, x):
def inter_y(x):
return self.a * (x + self.b)**2 + self.c
if x < self.p_min.x:
return self.p_min.y
elif x > self.p_max.x:
return self.p_max.y
else:
return inter_y(x)
def profit(self, x):
if x < self.p_min.x:
return 0
return x - self.y(x)
class TrailingStopStrategy(Strategy):
BREAK_EVEN_PERC = TAKER_FEE
MIN_PROFIT_PERC = BREAK_EVEN_PERC + 0.3
GOOD_PROFIT_PERC = MIN_PROFIT_PERC * 2.5
MAX_LOSS_PERC = -3.75
OFFER_PERC = 0.005
TRAILING_STOP = SquaredTrailingStop(Point(MIN_PROFIT_PERC, MIN_PROFIT_PERC/3*2), Point(GOOD_PROFIT_PERC, 0.1))
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