tailwind #9

Manually merged
peperunas merged 157 commits from tailwind into master 2020-12-28 18:38:52 +00:00
5 changed files with 70 additions and 17 deletions
Showing only changes of commit f9f14df519 - Show all commits

View File

@ -1,9 +1,11 @@
from time import sleep
from typing import Dict, List
from typing import Dict, List, Optional, Tuple
from bfxapi import Order
from bfxbot.bfxwrapper import BfxWrapper
from bfxbot.currency import Symbol
from bfxbot.models import SymbolStatus, Ticker, EventHandler, Strategy, Event, EventKind
from bfxbot.models import SymbolStatus, Ticker, EventHandler, Strategy, Event, EventKind, OFFER_PERC, PositionWrapper
class BfxBot:
@ -29,6 +31,14 @@ class BfxBot:
for s in self.symbols:
self.__status[s] = SymbolStatus(s)
def __position_wrapper_from_id(self, position_id) -> Optional[Tuple[PositionWrapper, SymbolStatus]]:
for s in self.__status.values():
pw = s.active_position_wrapper_from_id(position_id)
if pw:
return pw, s
return None
async def __update_status__(self):
active_positions = await self.__bfx.get_active_position()
@ -57,11 +67,45 @@ class BfxBot:
## TODO: handle _on_new_tick() from Strategy
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)
if not pw:
return None
is_long_pos = pw.position.amount < 0
pub_tick = await self.__bfx.get_public_ticker(pw.position.symbol)
bid_price = pub_tick[0]
ask_price = pub_tick[2]
if is_long_pos:
closing_price = bid_price * (1 - OFFER_PERC / 100)
else:
closing_price = ask_price * (1 + OFFER_PERC / 100)
return closing_price
def close_order(self, symbol: Symbol, order_id: int):
print(f"I would have closed order {order_id} for {symbol}")
def close_position(self, symbol: Symbol, position_id: int):
print(f"I would have closed order {position_id} for {symbol}")
async def close_position(self, position_id: int):
pw, ss = self.__position_wrapper_from_id(position_id)
if not pw:
print("Could not find open position!")
return
closing_price = await self.best_position_closing_price(pw.position.id)
amount = pw.position.amount * -1
open_orders = await self.__bfx.get_active_orders(pw.position.symbol)
if not open_orders:
await self.__bfx.submit_order(pw.position.symbol, closing_price, amount, Order.Type.LIMIT)
await ss.__add_event(Event(EventKind.ORDER_SUBMITTED, ss.current_tick))
def set_strategy(self, symbol, strategy: Strategy):
if symbol in self.__status:
@ -72,13 +116,13 @@ class BfxBot:
async def start(self):
await self.__update_status__()
def symbol_event_handler(self, symbol) -> EventHandler:
def symbol_event_handler(self, symbol) -> Optional[EventHandler]:
if symbol not in self.__status:
return None
return self.__status[symbol].eh
def symbol_status(self, symbol: Symbol) -> SymbolStatus:
def symbol_status(self, symbol: Symbol) -> Optional[SymbolStatus]:
if symbol not in self.__status:
return None

View File

@ -1,12 +1,16 @@
import inspect
import time
from enum import Enum
from typing import List, Dict, Tuple
from typing import List, Dict, Tuple, Optional
from bfxapi import Order, Position
from bfxbot.currency import Symbol
OFFER_PERC = 0.008
TAKER_FEE = 0.2
MAKER_FEE = 0.1
def __add_to_dict_list__(dict: Dict[int, List], k, v):
if k not in dict:
@ -59,6 +63,7 @@ class PositionState(Enum):
def __repr__(self):
return self.__str__()
class Ticker:
def __init__(self, sec) -> None:
self.seconds: int = sec
@ -142,12 +147,18 @@ class SymbolStatus:
def current_price(self):
return self.prices[self.current_tick]
def previous_pw(self, pid: int) -> PositionWrapper:
def previous_pw(self, pid: int) -> Optional[PositionWrapper]:
if self.current_tick == 1:
return None
return next(filter(lambda x: x.position.id == pid, self.positions[self.current_tick - 1]))
def active_position_wrapper_from_id(self, position_id: int) -> Optional[PositionWrapper]:
for pw in self.positions[self.current_tick]:
if pw.position.id == position_id:
return pw
return None
def set_tick_price(self, tick, price):
self.prices[tick] = price

View File

@ -1,8 +1,5 @@
from bfxbot.models import PositionWrapper
TAKER_FEE = 0.2
MAKER_FEE = 0.1
def net_pl_percentage(perc: float, reference_fee_perc: float):
return perc - reference_fee_perc

View File

@ -24,7 +24,7 @@ async def bot_loop():
await bot.update()
asyncio.new_event_loop()
loop = asyncio.new_event_loop()
dotenv.load_dotenv()
@ -58,9 +58,9 @@ def entry():
@socketio.on("close_position")
def on_close_position(message: dict):
position_id = message['position_id']
symbol= Symbol.from_str(message['symbol'])
bot.close_position(symbol, position_id)
loop.run_until_complete(bot.close_position(position_id))
@socketio.on('connect')
def on_connect():
@ -106,5 +106,6 @@ def on_any_event(event: Event, _):
"kind": event.kind.name
})
if __name__ == '__main__':
socketio.run(app, debug=True)

View File

@ -4,8 +4,9 @@ import sympy.abc
from bfxapi import Position
from sympy import Point, solve
from bfxbot.models import Strategy, PositionState, SymbolStatus, Event, EventKind, EventMetadata, PositionWrapper
from bfxbot.utils import TAKER_FEE, net_pl_percentage
from bfxbot.models import Strategy, PositionState, SymbolStatus, Event, EventKind, EventMetadata, PositionWrapper, \
TAKER_FEE
from bfxbot.utils import net_pl_percentage
class SquaredTrailingStop:
@ -47,7 +48,6 @@ class TrailingStopStrategy(Strategy):
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))