started refactoring

This commit is contained in:
Giulio De Pasquale 2020-11-30 09:12:43 +00:00
parent 77e507e204
commit 7521756115
5 changed files with 218 additions and 0 deletions

0
bfxbot/__init__.py Normal file
View File

87
bfxbot/bfxbot.py Normal file
View File

@ -0,0 +1,87 @@
import inspect
from typing import Dict
from bfxapi import Position
from bfxbot.bfxwrapper import BfxWrapper
from bfxbot.event import Event, EventKind
from bfxbot.status import Status, PositionState, Ticker
class BfxBot:
class EventHandler:
def __init__(self):
self.event_handlers = {}
self.state_handlers = {}
async def call_event(self, event: Event, status: Status):
value = event.kind.value
if value in self.event_handlers:
for h in self.event_handlers[value]:
if inspect.iscoroutinefunction(h):
await h(event, status)
else:
h(event, status)
async def call_state(self, state: PositionState, status: Status):
if state in self.state_handlers:
for h in self.state_handlers[state]:
if inspect.iscoroutinefunction(h):
await h(status)
else:
h(status)
def on_event(self, kind: EventKind):
value = kind.value
def registerhandler(handler):
if value in self.event_handlers:
self.event_handlers[value].append(handler)
else:
self.event_handlers[value] = [handler]
return handler
return registerhandler
def on_state(self, state: PositionState):
def registerhandler(handler):
if state in self.state_handlers:
self.state_handlers[state].append(handler)
else:
self.state_handlers[state] = [handler]
return handler
return registerhandler
def __init__(self, api_key: str, api_secret: str, tick_duration: int = 60):
self.bfx: BfxWrapper = BfxWrapper(api_key, api_secret)
self.status: Dict[str, Status] = {}
self.eh: BfxBot.EventHandler = BfxBot.EventHandler()
self.ticker: Ticker = Ticker(tick_duration)
await self.__update_status__()
async def __update_status__(self):
active_positions = await self.bfx.get_active_position()
for p in active_positions:
if p.symbol not in self.status:
self.status[p.symbol] = Status(p.symbol)
self.status[p.symbol].positions[self.ticker.current_tick].append(p)
for symbol in self.status.keys():
active_orders = await self.bfx.get_active_orders(symbol)
for o in active_orders:
if symbol not in self.status:
self.status[symbol] = Status(symbol)
self.status[symbol].orders[self.ticker.current_tick].append(o)
def __trigger__events(self):
return
async def update(self):
self.ticker.inc()
await self.__update_status__()

29
bfxbot/bfxwrapper.py Normal file
View File

@ -0,0 +1,29 @@
from bfxapi.rest.bfx_rest import BfxRest
class BfxWrapper(BfxRest):
def __init__(self, api_key: str, api_secret: str):
super().__init__(API_KEY=api_key, API_SECRET=api_secret)
async def get_current_prices(self, symbol) -> (float, float, float):
tickers = await self.get_public_ticker(symbol)
bid_price = tickers[0]
ask_price = tickers[2]
ticker_price = tickers[6]
return bid_price, ask_price, ticker_price
async def get_usd_balance(self):
balance = 0.0
wallets = await self.get_wallets()
for w in wallets:
if w.currency == "USD":
balance += w.balance
else:
current_price = await self.get_current_prices(f"t{w.currency}USD")
balance += current_price * w.balance
return balance

24
bfxbot/event.py Normal file
View File

@ -0,0 +1,24 @@
from enum import Enum
class EventKind(Enum):
NEW_MINIMUM = 1,
NEW_MAXIMUM = 2,
REACHED_LOSS = 3,
REACHED_BREAK_EVEN = 4,
REACHED_MIN_PROFIT = 5,
REACHED_GOOD_PROFIT = 6,
REACHED_MAX_LOSS = 7,
CLOSE_POSITION = 8,
TRAILING_STOP_SET = 9,
TRAILING_STOP_MOVED = 10,
ORDER_SUBMITTED = 11,
class Event:
def __init__(self, kind: EventKind, tick: int) -> None:
self.kind: EventKind = kind
self.tick: int = tick
def __repr__(self) -> str:
return f"{self.kind.name} @ Tick {self.tick}"

78
bfxbot/status.py Normal file
View File

@ -0,0 +1,78 @@
import time
from enum import Enum
from typing import List, Dict
from bfxapi import Position, Order
from bfxbot.bfxbot import BfxBot
from bfxbot.event import Event, EventKind
class Ticker:
def __init__(self, sec) -> None:
self.seconds: int = sec
self.start_time = time.time()
self.current_tick: int = 1
def inc(self):
self.current_tick += 1
class PositionState(Enum):
CRITICAL = -1,
LOSS = 0,
BREAK_EVEN = 1,
MINIMUM_PROFIT = 2,
PROFIT = 3
def color(self) -> str:
if self == self.LOSS or self == self.CRITICAL:
return "red"
elif self == self.BREAK_EVEN:
return "yellow"
else:
return "green"
class Status:
def __init__(self, symbol):
self.events: List[Event] = []
self.symbol = symbol
self.current_state: PositionState = PositionState.LOSS
self.stop_percentage: float = None
self.orders: Dict[int, List[Order]] = {}
self.positions: Dict[int, List[Position]] = {}
def last_events(self, n) -> List[Event]:
return self.events[-n:]
def last_position(self) -> Position:
return [self.ticker.current_tick][1]
async def add_event(self, event: Event, event_handler: BfxBot.EventHandler):
self.events.append(event)
await event_handler.call_event(event, self)
async def set_state(self, state: PositionState, event_handler: BfxBot.EventHandler, tick: int):
if self.current_state != state:
event: Event = None
if state == PositionState.CRITICAL:
event = Event(EventKind.REACHED_MAX_LOSS, tick)
elif state == PositionState.LOSS:
event = Event(EventKind.REACHED_LOSS, tick)
elif state == PositionState.BREAK_EVEN:
event = Event(EventKind.REACHED_BREAK_EVEN, tick)
elif state == PositionState.MINIMUM_PROFIT:
event = Event(EventKind.REACHED_MIN_PROFIT, tick)
elif state == PositionState.PROFIT:
event = Event(EventKind.REACHED_GOOD_PROFIT, tick)
self.events.append(event)
await event_handler.call_event(event, self)
self.current_state = state
await event_handler.call_state(self.current_state, self)
def get_current_state(self) -> PositionState:
return self.current_state