From ec35fb1366a0ca5a135bdb577b2657594e6274ad Mon Sep 17 00:00:00 2001 From: Giulio De Pasquale Date: Mon, 21 Dec 2020 12:54:40 +0000 Subject: [PATCH] updated types to support currency. implemented changes in both backend and frontend. balances are sent to frontend --- bfxbot/currency.py | 2 +- bfxbot/utils.py | 40 ++++++++++++++++++++++++++++++-- main.py | 19 ++++++++++------ websrc/components/Tables.tsx | 18 ++++++++------- websrc/types.ts | 44 +++++++++++++++++++++++------------- 5 files changed, 89 insertions(+), 34 deletions(-) diff --git a/bfxbot/currency.py b/bfxbot/currency.py index a0262f3..26deadb 100644 --- a/bfxbot/currency.py +++ b/bfxbot/currency.py @@ -29,4 +29,4 @@ class Symbol(Enum): elif currency in ("eth"): return Symbol.ETH else: - return NotImplementedError + return NotImplementedError \ No newline at end of file diff --git a/bfxbot/utils.py b/bfxbot/utils.py index 0e5c79a..2aebd83 100644 --- a/bfxbot/utils.py +++ b/bfxbot/utils.py @@ -1,17 +1,53 @@ +import re + +from bfxbot.bfxwrapper import Balance from bfxbot.models import PositionWrapper +class CurrencyPair: + def __init__(self, base: str, quote: str): + self.base: str = base + self.quote: str = quote + + @staticmethod + def from_str(string: str): + symbol_regex = re.compile("t(?P[a-zA-Z]{3})(?P[a-zA-Z]{3})") + + match = symbol_regex.match(string) + + if not match: + return None + + return CurrencyPair(match.group("base"), match.group("quote")) + + def net_pl_percentage(perc: float, reference_fee_perc: float): return perc - reference_fee_perc -def pos_to_json(pw: PositionWrapper): +def balance_to_json(balance: Balance): + return { + 'currency': balance.currency, + 'amount': balance.amount, + 'kind': balance.kind.value + } + + +def pw_to_posprop(pw: PositionWrapper): + pair = CurrencyPair.from_str(pw.position.symbol) + + if not pair: + raise ValueError + return { "id": pw.position.id, "amount": pw.position.amount, "base_price": pw.position.base_price, "state": str(pw.state()), - "symbol": pw.position.symbol, + "pair": { + "base": pair.base, + "quote": pair.quote + }, "profit_loss": pw.net_profit_loss(), "profit_loss_percentage": pw.net_profit_loss_percentage() } diff --git a/main.py b/main.py index 6e8e450..b7d0e1e 100755 --- a/main.py +++ b/main.py @@ -11,9 +11,10 @@ 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, PositionState -from bfxbot.utils import pos_to_json +from bfxbot.models import PositionWrapper, SymbolStatus, Event, EventKind +from bfxbot.utils import pw_to_posprop, balance_to_json from strategy import TrailingStopStrategy @@ -64,15 +65,16 @@ def on_close_position(message: dict): @socketio.on('connect') -def on_connect(): +async def on_connect(): # sleeping on exception to avoid race condition - ticks, prices, positions = [], [], [] + 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) @@ -80,7 +82,8 @@ def on_connect(): { "ticks": ticks, "prices": prices, - "positions": list(map(pos_to_json, positions)) + "positions": list(map(pw_to_posprop, positions)), + "balances": list(map(balance_to_json, balances)) }) @@ -100,15 +103,17 @@ async def on_any_state(pw: PositionWrapper, ss: SymbolStatus): @btc_eh.on_event(EventKind.NEW_TICK) -def on_new_tick(event: Event, status: SymbolStatus): +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(pos_to_json, positions))}) + "positions": list(map(pw_to_posprop, positions)), + "balances": list(map(balance_to_json, balances))}) @btc_eh.on_any_event() diff --git a/websrc/components/Tables.tsx b/websrc/components/Tables.tsx index 7f85f68..e8a3a5d 100644 --- a/websrc/components/Tables.tsx +++ b/websrc/components/Tables.tsx @@ -1,7 +1,6 @@ import React, {Component} from "react" import {PositionProp} from "../types"; import {ClosePositionModal} from "./Overlays"; -import {symbolToPair} from "../utils"; type PositionsTableState = { showConfirmation: boolean, @@ -56,7 +55,6 @@ export class PositionsTable extends Component<{ positions: Array } renderTableRows() { return this.props.positions.map((position) => { // TODO: move symbolToPair out of here? - const currencyPair = symbolToPair(position.symbol) const stateBg = "bg-".concat(this.stateColor(position.state)).concat("-100 ") const stateText = "text-".concat(this.stateColor(position.state)).concat("-800 ") const stateClass = "px-2 inline-flex text-xs leading-5 font-semibold rounded-full ".concat(stateBg).concat(stateText) @@ -72,23 +70,26 @@ export class PositionsTable extends Component<{ positions: Array } -
{currencyPair.base}/{currencyPair.quote}
+
{position.pair.base}/{position.pair.quote}
{/*
{position.}
*/} -
{position.base_price.toLocaleString()} {currencyPair.quote}/{currencyPair.base}
+
{position.base_price.toLocaleString()} {position.pair.quote}/{position.pair.base}
{/*
Insert total % here?
*/} -
{position.amount.toFixed(5)} {currencyPair.base}
+
{position.amount.toFixed(5)} {position.pair.base}
Insert total % here?
-
{position.profit_loss.toLocaleString()} {currencyPair.quote}
-
{position.profit_loss_percentage.toFixed(2)}%
+
{position.profit_loss.toLocaleString()} {position.pair.quote}
+
{position.profit_loss_percentage.toFixed(2)}% +
@@ -113,7 +114,8 @@ export class PositionsTable extends Component<{ positions: Array } render() { return (
- +
diff --git a/websrc/types.ts b/websrc/types.ts index f1a043b..7af6041 100644 --- a/websrc/types.ts +++ b/websrc/types.ts @@ -1,19 +1,26 @@ import {EventProp} from "./components/Events"; -export type PositionProp = { - id: number, - state: string, - base_price: number, +/******************************* + * Types + *******************************/ + +export type Balance = { + currency: string, amount: number, - symbol: string, - profit_loss: number, - profit_loss_percentage: number + // exchange / margin + kind: string +} + +export type CurrencyPair = { + base: string, + quote: string } export type FirstConnectMessage = { ticks: Array, prices: Array, - positions: Array + positions: Array, + balances: Array } export type NewEventMessage = { @@ -24,7 +31,8 @@ export type NewEventMessage = { export type NewTickMessage = { tick: number, price: number, - positions: Array + positions: Array, + balances: Array } export type PositionCloseMessage = { @@ -32,15 +40,19 @@ export type PositionCloseMessage = { position_id: number, } -export type CurrencyPair = { - base: string, - quote: string +export type PositionProp = { + id: number, + state: string, + base_price: number, + amount: number, + pair: CurrencyPair, + profit_loss: number, + profit_loss_percentage: number } -export type Currency = { - name: string, - short_name: string -} +/******************************* +* ENUMS +*******************************/ export enum EventName { NewTick = "new_tick",