sending new_ticks event

This commit is contained in:
Giulio De Pasquale 2020-12-10 16:29:26 +00:00
parent 11bba57343
commit 9955ddf08e
5 changed files with 68 additions and 40 deletions

View File

@ -1,13 +1,12 @@
from time import sleep from time import sleep
from typing import Dict from typing import Dict, List
from bfxbot.bfxwrapper import BfxWrapper from bfxbot.bfxwrapper import BfxWrapper
from bfxbot.currency import Symbol from bfxbot.currency import Symbol
from bfxbot.models import SymbolStatus, Ticker, EventHandler, Strategy from bfxbot.models import SymbolStatus, Ticker, EventHandler, Strategy, Event, EventKind
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, symbols: List[Symbol], tick_duration: int = 1, ):
if api_key is None: if api_key is None:
print("API_KEY is not set!") print("API_KEY is not set!")
raise ValueError raise ValueError
@ -20,25 +19,41 @@ class BfxBot:
self.status: Dict[Symbol, SymbolStatus] = {} self.status: Dict[Symbol, SymbolStatus] = {}
self.ticker: Ticker = Ticker(tick_duration) self.ticker: Ticker = Ticker(tick_duration)
if isinstance(symbols, Symbol):
symbols = [symbols]
self.symbols: List[Symbol] = symbols
# init symbol statuses
for s in self.symbols:
self.status[s] = SymbolStatus(s)
async def __update_status__(self): async def __update_status__(self):
active_positions = await self.bfx.get_active_position() active_positions = await self.bfx.get_active_position()
for p in active_positions: for symbol in self.status:
symbol = Symbol.from_str(p.symbol) # updating tick
self.status[symbol].current_tick = self.ticker.current_tick
if symbol not in self.status: # updating last price
self.status[symbol] = SymbolStatus(symbol) last_price = await self.bfx.get_current_prices(symbol)
last_price = last_price[0]
await self.status[symbol].add_position(p) self.status[symbol].set_price(self.ticker.current_tick, last_price)
for symbol in self.status.keys(): # updating positions
active_orders = await self.bfx.get_active_orders(symbol) for p in [x for x in active_positions if x.symbol == symbol]:
await self.status[p.symbol].add_position(p)
for o in active_orders: # # updating orders
if symbol not in self.status: # active_orders = await self.bfx.get_active_orders(symbol)
self.status[symbol] = SymbolStatus(symbol) #
# for o in active_orders:
# self.status[symbol].add_order(o)
# emitting event
await self.status[symbol].__add_event__(Event(EventKind.NEW_TICK, 0, self.ticker.current_tick))
self.status[symbol].add_order(o)
def event_handler(self, symbol) -> EventHandler: def event_handler(self, symbol) -> EventHandler:
if symbol not in self.status: if symbol not in self.status:

View File

@ -44,6 +44,7 @@ class EventKind(Enum):
TRAILING_STOP_SET = 9, TRAILING_STOP_SET = 9,
TRAILING_STOP_MOVED = 10, TRAILING_STOP_MOVED = 10,
ORDER_SUBMITTED = 11, ORDER_SUBMITTED = 11,
NEW_TICK = 12
class Ticker: class Ticker:
@ -93,6 +94,7 @@ class SymbolStatus:
def __init__(self, symbol: Symbol, strategy=None): def __init__(self, symbol: Symbol, strategy=None):
self.symbol = symbol self.symbol = symbol
self.eh = EventHandler() self.eh = EventHandler()
self.prices: Dict[int, float] = {}
self.events: List[Event] = [] self.events: List[Event] = []
self.orders: Dict[int, List[Order]] = {} self.orders: Dict[int, List[Order]] = {}
self.positions: Dict[int, List[PositionWrapper]] = {} self.positions: Dict[int, List[PositionWrapper]] = {}
@ -143,6 +145,8 @@ class SymbolStatus:
pw.set_state(state) pw.set_state(state)
await self.eh.call_state(self, pw) await self.eh.call_state(self, pw)
def set_price(self, tick, price):
self.prices[tick] = price
class Strategy: class Strategy:
""" """
@ -167,8 +171,10 @@ class EventHandler:
self.any_events = [] self.any_events = []
self.any_state = [] self.any_state = []
async def call_event(self, event: Event, status: SymbolStatus): async def call_event(self, status: SymbolStatus, event: Event):
value = event.kind.value value = event.kind.value
# print("CALLING EVENT: {}".format(event))
if value in self.event_handlers: if value in self.event_handlers:
for h in self.event_handlers[value]: for h in self.event_handlers[value]:
if inspect.iscoroutinefunction(h): if inspect.iscoroutinefunction(h):
@ -182,7 +188,9 @@ class EventHandler:
else: else:
h(event, status) h(event, status)
async def call_state(self, state: PositionState, status: SymbolStatus): async def call_state(self, status: SymbolStatus, pw: PositionWrapper):
state = pw.state
if state in self.state_handlers: if state in self.state_handlers:
for h in self.state_handlers[state]: for h in self.state_handlers[state]:
if inspect.iscoroutinefunction(h): if inspect.iscoroutinefunction(h):

40
main.py
View File

@ -492,20 +492,18 @@ import dotenv
from bfxbot import BfxBot from bfxbot import BfxBot
from bfxbot.currency import Symbol from bfxbot.currency import Symbol
from bfxbot.models import EventHandler, PositionState, SymbolStatus, Event from bfxbot.models import EventHandler, PositionState, SymbolStatus, Event, EventKind
from strategy import TrailingStopStrategy from strategy import TrailingStopStrategy
from flask import Flask, render_template from flask import Flask, render_template
from flask_socketio import SocketIO from flask_socketio import SocketIO
app = Flask(__name__) app = Flask(__name__)
socketio = SocketIO(app) socketio = SocketIO(app, async_mode="threading")
dotenv.load_dotenv() dotenv.load_dotenv()
loop = asyncio.new_event_loop() loop = asyncio.new_event_loop()
bot: BfxBot = None bot = None
eh: EventHandler = None
@app.route('/') @app.route('/')
def entry(): def entry():
@ -531,6 +529,7 @@ def entry():
# while True: # while True:
# await bot.update() # await bot.update()
from flask import request
@socketio.on("close") @socketio.on("close")
def on_message(message: dict): def on_message(message: dict):
@ -540,29 +539,30 @@ def on_message(message: dict):
@socketio.on('connect') @socketio.on('connect')
def start_bot(): def start_bot():
asyncio.set_event_loop(loop)
global bot global bot
global eh
asyncio.set_event_loop(loop)
API_KEY = os.getenv("API_KEY") API_KEY = os.getenv("API_KEY")
API_SECRET = os.getenv("API_SECRET") API_SECRET = os.getenv("API_SECRET")
bot = BfxBot(api_key=API_KEY, api_secret=API_SECRET) if not bot:
strategy = TrailingStopStrategy() bot = BfxBot(api_key=API_KEY, api_secret=API_SECRET, symbols=[Symbol.BTC], tick_duration=20)
bot.set_strategy(Symbol.BTC, strategy) strategy = TrailingStopStrategy()
eh = bot.event_handler(Symbol.BTC) bot.set_strategy(Symbol.BTC, strategy)
@eh.on_any_event()
def on_any_event(event: Event, status: SymbolStatus):
print("EMITTING")
socketio.emit("event", {"kind": "a"})
threading.Thread(target=lambda: asyncio.run(bot_loop())).start()
print("Bot started.")
threading.Thread(target=lambda: asyncio.run(bot_loop())).start()
print("Bot started.")
async def bot_loop(): async def bot_loop():
global bot
eh = bot.event_handler(Symbol.BTC)
@eh.on_event(EventKind.NEW_TICK)
def on_new_tick(event: Event, status: SymbolStatus):
socketio.emit("new_tick", {"tick": event.tick, "price": status.prices[event.tick]})
await bot.start() await bot.start()
while True: while True:

View File

@ -27,6 +27,12 @@ $(document).ready(function () {
}) })
}) })
socket.on("event", () => { socket.on("connect", function(socket) {
}) console.log("Connected");
});
socket.on("new_tick", function(data) {
console.log("Tick " + data['tick'] + "| Price: " + data['price']);
});
}); });

View File

@ -9,7 +9,6 @@
<script src="{{ url_for('static', filename='js/jquery-3.5.1.min.js') }}"></script> <script src="{{ url_for('static', filename='js/jquery-3.5.1.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/plotly-latest.min.js') }}"></script> <script src="{{ url_for('static', filename='js/plotly-latest.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/socket.io.min.js') }}"></script> <script src="{{ url_for('static', filename='js/socket.io.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/toast.js') }}"></script>
<script src="{{ url_for('static', filename='js/rustico.js') }}"></script> <script src="{{ url_for('static', filename='js/rustico.js') }}"></script>
</head> </head>