updated types to support currency. implemented changes in both backend and frontend. balances are sent to frontend
This commit is contained in:
parent
9829bd2c71
commit
ec35fb1366
@ -1,17 +1,53 @@
|
|||||||
|
import re
|
||||||
|
|
||||||
|
from bfxbot.bfxwrapper import Balance
|
||||||
from bfxbot.models import PositionWrapper
|
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<base>[a-zA-Z]{3})(?P<quote>[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):
|
def net_pl_percentage(perc: float, reference_fee_perc: float):
|
||||||
return perc - reference_fee_perc
|
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 {
|
return {
|
||||||
"id": pw.position.id,
|
"id": pw.position.id,
|
||||||
"amount": pw.position.amount,
|
"amount": pw.position.amount,
|
||||||
"base_price": pw.position.base_price,
|
"base_price": pw.position.base_price,
|
||||||
"state": str(pw.state()),
|
"state": str(pw.state()),
|
||||||
"symbol": pw.position.symbol,
|
"pair": {
|
||||||
|
"base": pair.base,
|
||||||
|
"quote": pair.quote
|
||||||
|
},
|
||||||
"profit_loss": pw.net_profit_loss(),
|
"profit_loss": pw.net_profit_loss(),
|
||||||
"profit_loss_percentage": pw.net_profit_loss_percentage()
|
"profit_loss_percentage": pw.net_profit_loss_percentage()
|
||||||
}
|
}
|
||||||
|
19
main.py
19
main.py
@ -11,9 +11,10 @@ from flask import Flask, render_template
|
|||||||
from flask_socketio import SocketIO
|
from flask_socketio import SocketIO
|
||||||
|
|
||||||
from bfxbot import BfxBot
|
from bfxbot import BfxBot
|
||||||
|
from bfxbot.bfxwrapper import Balance
|
||||||
from bfxbot.currency import Symbol
|
from bfxbot.currency import Symbol
|
||||||
from bfxbot.models import PositionWrapper, SymbolStatus, Event, EventKind, PositionState
|
from bfxbot.models import PositionWrapper, SymbolStatus, Event, EventKind
|
||||||
from bfxbot.utils import pos_to_json
|
from bfxbot.utils import pw_to_posprop, balance_to_json
|
||||||
from strategy import TrailingStopStrategy
|
from strategy import TrailingStopStrategy
|
||||||
|
|
||||||
|
|
||||||
@ -64,15 +65,16 @@ def on_close_position(message: dict):
|
|||||||
|
|
||||||
|
|
||||||
@socketio.on('connect')
|
@socketio.on('connect')
|
||||||
def on_connect():
|
async def on_connect():
|
||||||
# sleeping on exception to avoid race condition
|
# sleeping on exception to avoid race condition
|
||||||
ticks, prices, positions = [], [], []
|
ticks, prices, positions, balances = [], [], [], []
|
||||||
|
|
||||||
while not ticks or not prices:
|
while not ticks or not prices:
|
||||||
try:
|
try:
|
||||||
ticks = bot.symbol_status(Symbol.BTC).all_ticks()
|
ticks = bot.symbol_status(Symbol.BTC).all_ticks()
|
||||||
prices = bot.symbol_status(Symbol.BTC).all_prices()
|
prices = bot.symbol_status(Symbol.BTC).all_prices()
|
||||||
positions = bot.symbol_status(Symbol.BTC).current_positions()
|
positions = bot.symbol_status(Symbol.BTC).current_positions()
|
||||||
|
balances = await bot.get_balances()
|
||||||
except KeyError:
|
except KeyError:
|
||||||
sleep(1)
|
sleep(1)
|
||||||
|
|
||||||
@ -80,7 +82,8 @@ def on_connect():
|
|||||||
{
|
{
|
||||||
"ticks": ticks,
|
"ticks": ticks,
|
||||||
"prices": prices,
|
"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)
|
@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
|
tick = event.tick
|
||||||
price = status.prices[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 []
|
positions: List[PositionWrapper] = status.positions[event.tick] if event.tick in status.positions else []
|
||||||
|
|
||||||
socketio.emit("new_tick", {"tick": tick,
|
socketio.emit("new_tick", {"tick": tick,
|
||||||
"price": price,
|
"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()
|
@btc_eh.on_any_event()
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import React, {Component} from "react"
|
import React, {Component} from "react"
|
||||||
import {PositionProp} from "../types";
|
import {PositionProp} from "../types";
|
||||||
import {ClosePositionModal} from "./Overlays";
|
import {ClosePositionModal} from "./Overlays";
|
||||||
import {symbolToPair} from "../utils";
|
|
||||||
|
|
||||||
type PositionsTableState = {
|
type PositionsTableState = {
|
||||||
showConfirmation: boolean,
|
showConfirmation: boolean,
|
||||||
@ -56,7 +55,6 @@ export class PositionsTable extends Component<{ positions: Array<PositionProp> }
|
|||||||
renderTableRows() {
|
renderTableRows() {
|
||||||
return this.props.positions.map((position) => {
|
return this.props.positions.map((position) => {
|
||||||
// TODO: move symbolToPair out of here?
|
// TODO: move symbolToPair out of here?
|
||||||
const currencyPair = symbolToPair(position.symbol)
|
|
||||||
const stateBg = "bg-".concat(this.stateColor(position.state)).concat("-100 ")
|
const stateBg = "bg-".concat(this.stateColor(position.state)).concat("-100 ")
|
||||||
const stateText = "text-".concat(this.stateColor(position.state)).concat("-800 ")
|
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)
|
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<PositionProp> }
|
|||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td className="px-6 py-1 whitespace-nowrap">
|
<td className="px-6 py-1 whitespace-nowrap">
|
||||||
<div className="text-sm text-gray-900">{currencyPair.base}/{currencyPair.quote}</div>
|
<div className="text-sm text-gray-900">{position.pair.base}/{position.pair.quote}</div>
|
||||||
{/*<div className="text-sm text-gray-500">{position.}</div>*/}
|
{/*<div className="text-sm text-gray-500">{position.}</div>*/}
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td className="px-6 py-1 whitespace-nowrap">
|
<td className="px-6 py-1 whitespace-nowrap">
|
||||||
<div className="text-sm text-gray-900">{position.base_price.toLocaleString()} {currencyPair.quote}/{currencyPair.base}</div>
|
<div
|
||||||
|
className="text-sm text-gray-900">{position.base_price.toLocaleString()} {position.pair.quote}/{position.pair.base}</div>
|
||||||
{/*<div className="text-sm text-gray-500">Insert total % here?</div>*/}
|
{/*<div className="text-sm text-gray-500">Insert total % here?</div>*/}
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td className="px-6 py-1 whitespace-nowrap">
|
<td className="px-6 py-1 whitespace-nowrap">
|
||||||
<div className="text-sm text-gray-900">{position.amount.toFixed(5)} {currencyPair.base}</div>
|
<div className="text-sm text-gray-900">{position.amount.toFixed(5)} {position.pair.base}</div>
|
||||||
<div className="text-sm text-gray-500">Insert total % here?</div>
|
<div className="text-sm text-gray-500">Insert total % here?</div>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td className="px-6 py-1 whitespace-nowrap">
|
<td className="px-6 py-1 whitespace-nowrap">
|
||||||
<div className="text-sm text-gray-900 font-semibold">{position.profit_loss.toLocaleString()} {currencyPair.quote}</div>
|
<div
|
||||||
<div className={"text-sm ".concat(stateClass)}>{position.profit_loss_percentage.toFixed(2)}%</div>
|
className="text-sm text-gray-900 font-semibold">{position.profit_loss.toLocaleString()} {position.pair.quote}</div>
|
||||||
|
<div className={"text-sm ".concat(stateClass)}>{position.profit_loss_percentage.toFixed(2)}%
|
||||||
|
</div>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td className="px-6 py-1 whitespace-nowrap text-right text-sm font-medium">
|
<td className="px-6 py-1 whitespace-nowrap text-right text-sm font-medium">
|
||||||
@ -113,7 +114,8 @@ export class PositionsTable extends Component<{ positions: Array<PositionProp> }
|
|||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<ClosePositionModal positionId={this.state.positionToClose} toggleConfirmation={this.toggleConfirmation} show={this.state.showConfirmation}/>
|
<ClosePositionModal positionId={this.state.positionToClose} toggleConfirmation={this.toggleConfirmation}
|
||||||
|
show={this.state.showConfirmation}/>
|
||||||
<div className="-my-2 overflow-x-auto sm:-mx-6 lg:-mx-8">
|
<div className="-my-2 overflow-x-auto sm:-mx-6 lg:-mx-8">
|
||||||
<div className="py-2 align-middle inline-block min-w-full sm:px-6 lg:px-8">
|
<div className="py-2 align-middle inline-block min-w-full sm:px-6 lg:px-8">
|
||||||
<div className="shadow overflow-hidden border-b border-gray-200 sm:rounded-lg">
|
<div className="shadow overflow-hidden border-b border-gray-200 sm:rounded-lg">
|
||||||
|
@ -1,19 +1,26 @@
|
|||||||
import {EventProp} from "./components/Events";
|
import {EventProp} from "./components/Events";
|
||||||
|
|
||||||
export type PositionProp = {
|
/*******************************
|
||||||
id: number,
|
* Types
|
||||||
state: string,
|
*******************************/
|
||||||
base_price: number,
|
|
||||||
|
export type Balance = {
|
||||||
|
currency: string,
|
||||||
amount: number,
|
amount: number,
|
||||||
symbol: string,
|
// exchange / margin
|
||||||
profit_loss: number,
|
kind: string
|
||||||
profit_loss_percentage: number
|
}
|
||||||
|
|
||||||
|
export type CurrencyPair = {
|
||||||
|
base: string,
|
||||||
|
quote: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type FirstConnectMessage = {
|
export type FirstConnectMessage = {
|
||||||
ticks: Array<number>,
|
ticks: Array<number>,
|
||||||
prices: Array<number>,
|
prices: Array<number>,
|
||||||
positions: Array<PositionProp>
|
positions: Array<PositionProp>,
|
||||||
|
balances: Array<Balance>
|
||||||
}
|
}
|
||||||
|
|
||||||
export type NewEventMessage = {
|
export type NewEventMessage = {
|
||||||
@ -24,7 +31,8 @@ export type NewEventMessage = {
|
|||||||
export type NewTickMessage = {
|
export type NewTickMessage = {
|
||||||
tick: number,
|
tick: number,
|
||||||
price: number,
|
price: number,
|
||||||
positions: Array<PositionProp>
|
positions: Array<PositionProp>,
|
||||||
|
balances: Array<Balance>
|
||||||
}
|
}
|
||||||
|
|
||||||
export type PositionCloseMessage = {
|
export type PositionCloseMessage = {
|
||||||
@ -32,15 +40,19 @@ export type PositionCloseMessage = {
|
|||||||
position_id: number,
|
position_id: number,
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CurrencyPair = {
|
export type PositionProp = {
|
||||||
base: string,
|
id: number,
|
||||||
quote: string
|
state: string,
|
||||||
|
base_price: number,
|
||||||
|
amount: number,
|
||||||
|
pair: CurrencyPair,
|
||||||
|
profit_loss: number,
|
||||||
|
profit_loss_percentage: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Currency = {
|
/*******************************
|
||||||
name: string,
|
* ENUMS
|
||||||
short_name: string
|
*******************************/
|
||||||
}
|
|
||||||
|
|
||||||
export enum EventName {
|
export enum EventName {
|
||||||
NewTick = "new_tick",
|
NewTick = "new_tick",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user