# #!/usr/bin/env python import asyncio import os import threading from time import sleep from typing import List import dotenv from flask import Flask, render_template from flask_socketio import SocketIO from bfxbot import BfxBot from bfxbot.bfxwrapper import Balance from bfxbot.currency import Symbol from bfxbot.models import PositionWrapper, SymbolStatus, Event, EventKind from bfxbot.utils import pw_to_posprop, balance_to_json from strategy import TrailingStopStrategy async def bot_loop(): await bot.start() while True: await bot.update() loop = asyncio.new_event_loop() dotenv.load_dotenv() API_KEY = os.getenv("API_KEY") API_SECRET = os.getenv("API_SECRET") app = Flask(__name__) socketio = SocketIO(app, async_mode="threading") bot = BfxBot(api_key=API_KEY, api_secret=API_SECRET, symbols=[Symbol.BTC], tick_duration=20) strategy = TrailingStopStrategy() bot.set_strategy(Symbol.BTC, strategy) btc_eh = bot.symbol_event_handler(Symbol.BTC) # initializing and starting bot on other thread threading.Thread(target=lambda: asyncio.run(bot_loop())).start() ################################### # Flask callbacks ################################### @app.route('/') def entry(): return render_template('index.html') ################################### # Socker.IO callbacks ################################### @socketio.on("close_position") def on_close_position(message: dict): position_id = message['position_id'] loop.run_until_complete(bot.close_position(position_id)) @socketio.on('connect') async def on_connect(): # sleeping on exception to avoid race condition ticks, prices, positions, balances = [], [], [], [] while not ticks or not prices: try: ticks = bot.symbol_status(Symbol.BTC).all_ticks() prices = bot.symbol_status(Symbol.BTC).all_prices() positions = bot.symbol_status(Symbol.BTC).current_positions() balances = await bot.get_balances() except KeyError: sleep(1) socketio.emit("first_connect", { "ticks": ticks, "prices": prices, "positions": list(map(pw_to_posprop, positions)), "balances": list(map(balance_to_json, balances)) }) ################################### # Bot callbacks ################################### @btc_eh.on_event(EventKind.CLOSE_POSITION) async def on_close_position(event: Event, _): print("CLOSING!") await bot.close_position(event.metadata.position_id) @btc_eh.on_any_position_state() async def on_any_state(pw: PositionWrapper, ss: SymbolStatus): await strategy.update_stop_percentage(pw, ss) @btc_eh.on_event(EventKind.NEW_TICK) async def on_new_tick(event: Event, status: SymbolStatus): tick = event.tick price = status.prices[event.tick] balances: List[Balance] = await bot.get_balances() positions: List[PositionWrapper] = status.positions[event.tick] if event.tick in status.positions else [] socketio.emit("new_tick", {"tick": tick, "price": price, "positions": list(map(pw_to_posprop, positions)), "balances": list(map(balance_to_json, balances))}) @btc_eh.on_any_event() def on_any_event(event: Event, _): socketio.emit("new_event", { "tick": event.tick, "kind": event.kind.name }) if __name__ == '__main__': socketio.run(app)