Merge branch 'refactor' of ssh://giugl.io.gitea:10022/peperunas/gkaching into refactor
This commit is contained in:
commit
dcd91eaab8
@ -8,6 +8,14 @@ from bfxbot.models import SymbolStatus, Ticker, EventHandler, Strategy
|
|||||||
|
|
||||||
class BfxBot:
|
class BfxBot:
|
||||||
def __init__(self, api_key: str, api_secret: str, tick_duration: int = 1):
|
def __init__(self, api_key: str, api_secret: str, tick_duration: int = 1):
|
||||||
|
if api_key is None:
|
||||||
|
print("API_KEY is not set!")
|
||||||
|
raise ValueError
|
||||||
|
|
||||||
|
if api_secret is None:
|
||||||
|
print("API_SECRET is not set!")
|
||||||
|
raise ValueError
|
||||||
|
|
||||||
self.bfx: BfxWrapper = BfxWrapper(api_key, api_secret)
|
self.bfx: BfxWrapper = BfxWrapper(api_key, api_secret)
|
||||||
self.status: Dict[Symbol, SymbolStatus] = {}
|
self.status: Dict[Symbol, SymbolStatus] = {}
|
||||||
self.ticker: Ticker = Ticker(tick_duration)
|
self.ticker: Ticker = Ticker(tick_duration)
|
||||||
|
68
main.py
68
main.py
@ -485,70 +485,34 @@
|
|||||||
# if __name__ == "__main__":
|
# if __name__ == "__main__":
|
||||||
# asyncio.run(Screen.wrapper(main))
|
# asyncio.run(Screen.wrapper(main))
|
||||||
import asyncio
|
import asyncio
|
||||||
import shutil
|
import os
|
||||||
from typing import List
|
|
||||||
|
|
||||||
from asciimatics.screen import Screen, ManagedScreen
|
import dotenv
|
||||||
from asciimatics.widgets import Frame, Layout, Text
|
|
||||||
from bfxapi import Position
|
|
||||||
|
|
||||||
from bfxbot import BfxBot
|
from bfxbot import BfxBot
|
||||||
import dotenv
|
|
||||||
import os
|
|
||||||
import bfxapi
|
|
||||||
|
|
||||||
from bfxbot.currency import Symbol
|
from bfxbot.currency import Symbol
|
||||||
from bfxbot.models import Strategy, SymbolStatus, PositionState, Event, EventKind
|
from bfxbot.models import PositionState
|
||||||
from bfxbot.utils import TAKER_FEE, net_pl_percentage
|
|
||||||
from strategy import TrailingStopStrategy
|
from strategy import TrailingStopStrategy
|
||||||
|
|
||||||
dotenv.load_dotenv()
|
dotenv.load_dotenv()
|
||||||
|
API_KEY = os.getenv("API_KEY")
|
||||||
|
API_SECRET = os.getenv("API_SECRET")
|
||||||
|
|
||||||
|
bot = BfxBot(api_key=API_KEY, api_secret=API_SECRET)
|
||||||
|
strategy = TrailingStopStrategy()
|
||||||
|
bot.set_strategy(Symbol.BTC, strategy)
|
||||||
|
eh = bot.event_handler(Symbol.BTC)
|
||||||
|
|
||||||
|
|
||||||
|
@eh.on_state(PositionState.PROFIT)
|
||||||
|
def on_min_profit(ss, pw):
|
||||||
|
print("Minimum profit!")
|
||||||
|
|
||||||
async def main():
|
async def main():
|
||||||
API_KEY = os.getenv("API_KEY")
|
|
||||||
API_SECRET = os.getenv("API_SECRET")
|
|
||||||
|
|
||||||
if API_KEY is None:
|
|
||||||
print("API_KEY is not set! Set the var in the .env file.")
|
|
||||||
return
|
|
||||||
|
|
||||||
if API_SECRET is 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, tick_duration=20)
|
|
||||||
strategy = TrailingStopStrategy()
|
|
||||||
bot.set_strategy(Symbol.BTC, strategy)
|
|
||||||
eh = bot.event_handler(Symbol.BTC)
|
|
||||||
|
|
||||||
await bot.start()
|
await bot.start()
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
await bot_loop(bot)
|
await bot.update()
|
||||||
|
|
||||||
|
|
||||||
@ManagedScreen
|
|
||||||
async def bot_loop(bot: BfxBot, screen: Screen = None):
|
|
||||||
prepare_tui(screen)
|
|
||||||
screen.play()
|
|
||||||
|
|
||||||
await bot.update()
|
|
||||||
|
|
||||||
def prepare_tui(screen: Screen):
|
|
||||||
w, h = shutil.get_terminal_size()
|
|
||||||
|
|
||||||
frame = Frame(screen, w, h, has_border=False)
|
|
||||||
|
|
||||||
info_layout = Layout([1])
|
|
||||||
graph_layout = Layout([1])
|
|
||||||
footer_layout = Layout([1])
|
|
||||||
|
|
||||||
frame.add_layout(info_layout)
|
|
||||||
frame.add_layout(graph_layout)
|
|
||||||
frame.add_layout(footer_layout)
|
|
||||||
|
|
||||||
info_layout.add_widget(Text(label="Test"))
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
asyncio.run(main())
|
asyncio.run(main())
|
@ -1,5 +1,2 @@
|
|||||||
asciimatics==1.12.0
|
python-dotenv~=0.15.0
|
||||||
asyncio==3.4.3
|
sympy~=1.7
|
||||||
playsound==1.2.2
|
|
||||||
termcolor==1.1.0
|
|
||||||
termplotlib==0.3.2
|
|
60
strategy.py
60
strategy.py
@ -1,22 +1,60 @@
|
|||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
from bfxapi import Position
|
import sympy.abc
|
||||||
|
from sympy import Point, solve
|
||||||
|
|
||||||
from bfxbot.models import Strategy, PositionState, SymbolStatus, Event, EventKind
|
from bfxbot.models import Strategy, PositionState, SymbolStatus, Event, EventKind
|
||||||
from bfxbot.utils import TAKER_FEE, net_pl_percentage
|
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):
|
class TrailingStopStrategy(Strategy):
|
||||||
BREAK_EVEN_PERC = TAKER_FEE
|
BREAK_EVEN_PERC = TAKER_FEE
|
||||||
MIN_PROFIT_PERC = TAKER_FEE * 2.5
|
MIN_PROFIT_PERC = BREAK_EVEN_PERC + 0.3
|
||||||
GOOD_PROFIT_PERC = MIN_PROFIT_PERC * 1.5
|
GOOD_PROFIT_PERC = MIN_PROFIT_PERC * 2.5
|
||||||
MAX_LOSS_PERC = -3.75
|
MAX_LOSS_PERC = -3.75
|
||||||
OFFER_PERC = 0.01
|
OFFER_PERC = 0.005
|
||||||
|
|
||||||
TRAIL_STOP_PERCENTAGES = {
|
TRAILING_STOP = SquaredTrailingStop(Point(MIN_PROFIT_PERC, MIN_PROFIT_PERC/3*2), Point(GOOD_PROFIT_PERC, 0.1))
|
||||||
PositionState.MINIMUM_PROFIT: 0.27,
|
|
||||||
PositionState.PROFIT: 0.14
|
|
||||||
}
|
|
||||||
|
|
||||||
def position_on_tick(self, position: Position, ss: SymbolStatus) -> (PositionState, List[Event]):
|
def position_on_tick(self, position: Position, ss: SymbolStatus) -> (PositionState, List[Event]):
|
||||||
events = []
|
events = []
|
||||||
@ -38,16 +76,18 @@ class TrailingStopStrategy(Strategy):
|
|||||||
if not prev or prev.state == state:
|
if not prev or prev.state == state:
|
||||||
return state, events
|
return state, events
|
||||||
|
|
||||||
if state ==PositionState.PROFIT:
|
if state == PositionState.PROFIT:
|
||||||
events.append(Event(EventKind.REACHED_GOOD_PROFIT, position.id, ss.current_tick))
|
events.append(Event(EventKind.REACHED_GOOD_PROFIT, position.id, ss.current_tick))
|
||||||
elif state == PositionState.MINIMUM_PROFIT:
|
elif state == PositionState.MINIMUM_PROFIT:
|
||||||
events.append(Event(EventKind.REACHED_MIN_PROFIT, position.id, ss.current_tick))
|
events.append(Event(EventKind.REACHED_MIN_PROFIT, position.id, ss.current_tick))
|
||||||
elif state == PositionState.BREAK_EVEN:
|
elif state == PositionState.BREAK_EVEN:
|
||||||
events.append(Event(EventKind.REACHED_BREAK_EVEN, position.id, ss.current_tick))
|
events.append(Event(EventKind.REACHED_BREAK_EVEN, position.id, ss.current_tick))
|
||||||
elif state== PositionState.LOSS:
|
elif state == PositionState.LOSS:
|
||||||
events.append(Event(EventKind.REACHED_LOSS, position.id, ss.current_tick))
|
events.append(Event(EventKind.REACHED_LOSS, position.id, ss.current_tick))
|
||||||
else:
|
else:
|
||||||
events.append(Event(EventKind.REACHED_MAX_LOSS, position.id, ss.current_tick))
|
events.append(Event(EventKind.REACHED_MAX_LOSS, position.id, ss.current_tick))
|
||||||
events.append(Event(EventKind.CLOSE_POSITION, position.id, ss.current_tick))
|
events.append(Event(EventKind.CLOSE_POSITION, position.id, ss.current_tick))
|
||||||
|
|
||||||
return state, events
|
return state, events
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user