Commit ad6f506a authored by Cranky Kernel's avatar Cranky Kernel

webapp: add binance balance view

parent 9e2dad93
Pipeline #53008339 passed with stage
in 12 minutes and 38 seconds
......@@ -26,6 +26,7 @@
doesn't. https://gitlab.com/crankykernel/maker/issues/52
- Provide visiable health status in the
UI. https://gitlab.com/crankykernel/maker/issues/42
- Add simple Binance balance view.
[Full Changelog](https://gitlab.com/crankykernel/maker/compare/0.3.2...master)
......
......@@ -774,7 +774,8 @@
"ansi-regex": {
"version": "2.1.1",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"aproba": {
"version": "1.2.0",
......@@ -1189,7 +1190,8 @@
"safe-buffer": {
"version": "5.1.1",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"safer-buffer": {
"version": "2.1.2",
......@@ -1245,6 +1247,7 @@
"version": "3.0.1",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"ansi-regex": "^2.0.0"
}
......@@ -1288,12 +1291,14 @@
"wrappy": {
"version": "1.0.2",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"yallist": {
"version": "3.0.2",
"bundled": true,
"dev": true
"dev": true,
"optional": true
}
}
},
......@@ -3043,7 +3048,6 @@
"version": "1.1.11",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
......@@ -3058,8 +3062,7 @@
"code-point-at": {
"version": "1.1.0",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"concat-map": {
"version": "0.0.1",
......@@ -3070,8 +3073,7 @@
"console-control-strings": {
"version": "1.1.0",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"core-util-is": {
"version": "1.0.2",
......@@ -3188,8 +3190,7 @@
"inherits": {
"version": "2.0.3",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"ini": {
"version": "1.3.5",
......@@ -3201,7 +3202,6 @@
"version": "1.0.0",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
......@@ -3216,7 +3216,6 @@
"version": "3.0.4",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
......@@ -3224,14 +3223,12 @@
"minimist": {
"version": "0.0.8",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"minipass": {
"version": "2.2.4",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"safe-buffer": "^5.1.1",
"yallist": "^3.0.0"
......@@ -3250,7 +3247,6 @@
"version": "0.5.1",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"minimist": "0.0.8"
}
......@@ -3331,8 +3327,7 @@
"number-is-nan": {
"version": "1.0.1",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"object-assign": {
"version": "4.1.1",
......@@ -3344,7 +3339,6 @@
"version": "1.4.0",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"wrappy": "1"
}
......@@ -3466,7 +3460,6 @@
"version": "1.0.2",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
......@@ -8030,7 +8023,6 @@
"version": "1.1.11",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
......@@ -8045,8 +8037,7 @@
"code-point-at": {
"version": "1.1.0",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"concat-map": {
"version": "0.0.1",
......@@ -8057,8 +8048,7 @@
"console-control-strings": {
"version": "1.1.0",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"core-util-is": {
"version": "1.0.2",
......@@ -8175,8 +8165,7 @@
"inherits": {
"version": "2.0.3",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"ini": {
"version": "1.3.5",
......@@ -8188,7 +8177,6 @@
"version": "1.0.0",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
......@@ -8203,7 +8191,6 @@
"version": "3.0.4",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
......@@ -8211,14 +8198,12 @@
"minimist": {
"version": "0.0.8",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"minipass": {
"version": "2.2.4",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"safe-buffer": "^5.1.1",
"yallist": "^3.0.0"
......@@ -8237,7 +8222,6 @@
"version": "0.5.1",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"minimist": "0.0.8"
}
......@@ -8318,8 +8302,7 @@
"number-is-nan": {
"version": "1.0.1",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"object-assign": {
"version": "4.1.1",
......@@ -8331,7 +8314,6 @@
"version": "1.4.0",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"wrappy": "1"
}
......@@ -8453,7 +8435,6 @@
"version": "1.0.2",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
......
......@@ -21,6 +21,7 @@ import {HistoryComponent} from './history/history.component';
import {TradeDetailComponent} from './trade-detail/trade-detail.component';
import {LoginComponent} from "./login/login.component";
import {CompositeGuard} from "./composite.guard";
import {BinanceBalancesComponent} from "./binance-balances/binance-balances.component";
const routes: Routes = [
{
......@@ -67,6 +68,17 @@ const routes: Routes = [
configRequired: true,
}
},
{
path: "binance/balances",
component: BinanceBalancesComponent,
canActivate: [
CompositeGuard,
],
data: {
authRequired: true,
configRequired: true,
}
},
{
path: "login",
pathMatch: "full",
......
......@@ -16,6 +16,9 @@
<li class="nav-item" routerLinkActive="active">
<a class="nav-link" [routerLink]="['/history']">History</a>
</li>
<li class="nav-item" routerLinkActive="active">
<a class="nav-link" [routerLink]="['/binance/balances']">Balances</a>
</li>
</ul>
<ul class="navbar-nav">
......
......@@ -41,6 +41,7 @@ import {TradeTableRowComponent} from './trade-table-row/trade-table-row.componen
import {TrailingProfitFormComponent} from './trailingprofitform/trailing-profit-form.component';
import {AboutComponent} from './about/about.component';
import {LoginComponent} from './login/login.component';
import { BinanceBalancesComponent } from './binance-balances/binance-balances.component';
fontawesome.library.add(faCog);
fontawesome.library.add(faQuestion);
......@@ -60,6 +61,7 @@ fontawesome.library.add(faSyncAlt);
TradeDetailComponent,
AboutComponent,
LoginComponent,
BinanceBalancesComponent,
],
imports: [
// Angular modules.
......
......@@ -73,7 +73,6 @@ export class BinanceApiService {
return this.makerApi.get("/api/binance/proxy/getAccount")
.pipe(map((restResponse: BinanceRestAccountInfoResrponse) => {
const accountInfo = BinanceAccountInfo.fromRest(restResponse);
console.log(accountInfo);
return accountInfo;
}));
}
......@@ -129,19 +128,19 @@ export interface BuyOrderResponse {
trade_id: string;
}
export interface StreamBalance {
export interface BinanceStreamBalanceResponse {
a: string; // Asset.
f: string; // Free amount.
l: string; // Locked amount.
}
export interface RestBalance {
export interface BinanceRestBalanceResponse {
asset: string;
free: string;
locked: string;
}
export class Balance {
export class BinanceBalance {
asset: string;
......@@ -149,16 +148,16 @@ export class Balance {
locked: number;
static fromRest(raw: RestBalance): Balance {
const balance = new Balance();
static fromRest(raw: BinanceRestBalanceResponse): BinanceBalance {
const balance = new BinanceBalance();
balance.asset = raw.asset;
balance.free = +raw.free;
balance.locked = +raw.locked;
return balance;
}
static fromStream(raw: StreamBalance): Balance {
const balance = new Balance();
static fromStream(raw: BinanceStreamBalanceResponse): BinanceBalance {
const balance = new BinanceBalance();
balance.asset = raw.a;
balance.free = +raw.f;
balance.locked = +raw.l;
......@@ -167,29 +166,29 @@ export class Balance {
}
export interface BinanceRestAccountInfoResrponse {
balances: RestBalance[];
balances: BinanceRestBalanceResponse[];
}
export interface BinanceStreamAccountInfoResponse {
B: StreamBalance[];
B: BinanceStreamBalanceResponse[];
}
export class BinanceAccountInfo {
balances: Balance[] = null;
balances: BinanceBalance[] = null;
static fromRest(raw: BinanceRestAccountInfoResrponse): BinanceAccountInfo {
const accountInfo = new BinanceAccountInfo();
accountInfo.balances = raw.balances.map((b): Balance => {
return Balance.fromRest(b);
accountInfo.balances = raw.balances.map((b): BinanceBalance => {
return BinanceBalance.fromRest(b);
});
return accountInfo;
}
static fromStream(raw: BinanceStreamAccountInfoResponse): BinanceAccountInfo {
const accountInfo = new BinanceAccountInfo();
accountInfo.balances = raw.B.map((b): Balance => {
return Balance.fromStream(b);
accountInfo.balances = raw.B.map((b): BinanceBalance => {
return BinanceBalance.fromStream(b);
});
return accountInfo;
}
......
<div class="container-fluid">
<div class="card">
<div class="card-header">
Binance Balances
</div>
<div class="card-body">
<table class="table">
<tr>
<th>Asset</th>
<th>Total</th>
<th>Free</th>
<th>Locked</th>
</tr>
<tr *ngFor="let b of balances">
<td>{{b.asset}}</td>
<td>{{b.total}}</td>
<td>{{b.free}}</td>
<td>{{b.locked}}</td>
</tr>
</table>
</div>
</div>
</div>
.card-body {
padding: 0;
}
.table {
margin-bottom: 0;
}
\ No newline at end of file
// Copyright (C) 2018 Cranky Kernel
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import {Component, OnInit} from '@angular/core';
import {BinanceAccountInfo, BinanceApiService, BinanceBalance} from "../binance-api.service";
@Component({
selector: 'app-binance-balances',
templateUrl: './binance-balances.component.html',
styleUrls: ['./binance-balances.component.scss']
})
export class BinanceBalancesComponent implements OnInit {
accountInfo: BinanceAccountInfo = null;
balances: BalanceEntry[] = [];
constructor(private binanceApi: BinanceApiService) {
}
ngOnInit() {
this.binanceApi.getAccountInfo().subscribe((accountInfo) => {
this.accountInfo = accountInfo;
this.balances = accountInfo.balances
.map((binanceBalance) => {
let balance: BalanceEntry = <BalanceEntry>binanceBalance;
balance.total = balance.free + balance.locked;
return balance;
})
.filter((balance) => {
return balance.total > 0;
})
.sort((a, b) => {
return a.total - b.total;
})
});
}
}
interface BalanceEntry extends BinanceBalance {
total: number;
}
\ No newline at end of file
......@@ -14,7 +14,7 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import {AfterViewInit, Component, OnDestroy, OnInit, ViewChild} from "@angular/core";
import {BinanceAccountInfo, AggTrade, Balance, BinanceApiService} from "../binance-api.service";
import {BinanceAccountInfo, AggTrade, BinanceBalance, BinanceApiService} from "../binance-api.service";
import {Observable} from "rxjs";
import {BinanceService, LimitSellType, OpenTradeOptions, PriceSource} from "../binance.service";
import {switchMap, tap} from "rxjs/operators";
......@@ -113,7 +113,7 @@ export class TradeComponent implements OnInit, OnDestroy, AfterViewInit {
offsetTicks: 0,
};
balances: { [key: string]: Balance } = {};
balances: { [key: string]: BinanceBalance } = {};
private tradeSubscription: Subscription = null;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment