111 lines
2.8 KiB
Python
Executable File
111 lines
2.8 KiB
Python
Executable File
# #!/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.currency import Symbol
|
|
from bfxbot.models import PositionWrapper, SymbolStatus, Event, EventKind
|
|
from strategy import TrailingStopStrategy
|
|
|
|
|
|
async def bot_loop():
|
|
await bot.start()
|
|
|
|
while True:
|
|
await bot.update()
|
|
|
|
|
|
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)
|
|
bot.set_strategy(Symbol.BTC, TrailingStopStrategy())
|
|
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']
|
|
symbol= Symbol.from_str(message['symbol'])
|
|
|
|
bot.close_position(symbol, position_id)
|
|
|
|
@socketio.on('connect')
|
|
def on_connect():
|
|
# sleeping on exception to avoid race condition
|
|
ticks, prices = [], []
|
|
|
|
while not ticks or not prices:
|
|
try:
|
|
ticks = bot.symbol_status(Symbol.BTC).all_ticks()
|
|
prices = bot.symbol_status(Symbol.BTC).all_prices()
|
|
except KeyError:
|
|
sleep(1)
|
|
|
|
socketio.emit("first_connect",
|
|
{"ticks": ticks,
|
|
"prices": prices})
|
|
|
|
|
|
###################################
|
|
# Bot callbacks
|
|
###################################
|
|
|
|
@btc_eh.on_event(EventKind.NEW_TICK)
|
|
def on_new_tick(event: Event, status: SymbolStatus):
|
|
# TODO: finalize JSON structure
|
|
def pos_to_json(pw: PositionWrapper):
|
|
return {
|
|
"id": pw.position.id,
|
|
"amount": pw.position.amount,
|
|
"base_price": pw.position.base_price,
|
|
"state": str(pw.state()),
|
|
"symbol": pw.position.symbol,
|
|
"profit_loss": pw.net_profit_loss(),
|
|
"profit_loss_percentage": pw.net_profit_loss_percentage()
|
|
}
|
|
|
|
tick = event.tick
|
|
price = status.prices[event.tick]
|
|
|
|
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(pos_to_json, positions))})
|
|
|
|
|
|
if __name__ == '__main__':
|
|
socketio.run(app, debug=True)
|