Skip to content

Commit

Permalink
Added editable orders to +portfolios client.
Browse files Browse the repository at this point in the history
████ ███  To request new features or in case this commit breaks something for you,
████ ███  please, create a new github issue with all possible information for me,
▓███▀█▄   but never share your API Keys!
▒▓██ ███
░▒▓█ ███  Signed-off-by: Carles Tubio <[email protected]>
 _________________________________________
/ Hello, WORLD!                           \
|                                         |
\ pssst.. 1.00000000 BTC = 61487.64 EUR.  /
 -----------------------------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||
  • Loading branch information
ctubio committed Oct 16, 2024
1 parent 4be0d1e commit fea4795
Show file tree
Hide file tree
Showing 8 changed files with 331 additions and 210 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ K ?= K.sh
MAJOR = 0
MINOR = 7
PATCH = 0
BUILD = 35
BUILD = 36

OBLIGATORY = DISCLAIMER: This is strict non-violent software: \n$\
if you hurt other living creatures, please stop; \n$\
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ to control a fully configurable high frequency trading engine, with all features
</details>

<details><summary><b>K-+portfolios</b> <sup>(web UI + CLI)</sup></summary>
to show all balances and orders from one exchange, with buttons to cancel orders and links to go to markets:<br />
to show all balances and orders from one exchange, with buttons to edit or cancel orders and links to go to markets:<br />

![+portfolios UI Preview](https://github.com/user-attachments/assets/3dd3488a-a466-4817-89f7-a6d581ddac9e)
</details>
Expand Down
54 changes: 39 additions & 15 deletions src/bin/+portfolios/+portfolios.client/Orders.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {Component, Input} from '@angular/core';

import {GridOptions, GridApi} from 'ag-grid-community';
import {GridOptions, GridApi, CellValueChangedEvent} from 'ag-grid-community';

import {Shared, Socket, Models} from 'lib/K';

Expand Down Expand Up @@ -32,13 +32,16 @@ import {Shared, Socket, Models} from 'lib/K';
(window:resize)="onGridReady($event)"
(gridReady)="onGridReady($event)"
(cellClicked)="onCellClicked($event)"
(cellValueChanged)="onCellValueChanged($event)"
[gridOptions]="grid"></ag-grid-angular>
</div>`
})
export class OrdersComponent {

private fireCxl: Socket.IFire<Models.OrderCancelRequestFromUI> = new Socket.Fire(Models.Topics.CancelOrder);

private editCxl: Socket.IFire<Models.OrderEditRequestFromUI> = new Socket.Fire(Models.Topics.EditOrder);

@Input() product: Models.ProductAdvertisement;

private best_ask: number;
Expand Down Expand Up @@ -112,6 +115,17 @@ export class OrdersComponent {
field: 'price',
headerName: 'price',
sort: 'desc',
editable: true,
cellEditor: 'agNumberCellEditor',
cellEditorSelector: (params) => {
return { params: {
min: 0,
precision: params.data.pricePrecision,
step: Math.pow(10, -params.data.pricePrecision),
showStepperButtons: true
} };
},
cellRenderer: (params) => '<span style="display: inline-block;">&#9998;</span>' + params.value,
cellClassRules: {
'sell': 'data.side == "Ask"',
'buy': 'data.side == "Bid"'
Expand All @@ -121,6 +135,7 @@ export class OrdersComponent {
field: 'quantity',
headerName: 'qty',
suppressSizeToFit: true,
cellRenderer: (params) => params.value.toFixed(params.data.quantityPrecision),
cellClassRules: {
'sell': 'data.side == "Ask"',
'buy': 'data.side == "Bid"'
Expand All @@ -129,6 +144,7 @@ export class OrdersComponent {
width: 74,
field: 'value',
headerName: 'value',
cellRenderer: (params) => params.value.toFixed(params.data.pricePrecision),
cellClassRules: {
'sell': 'data.side == "Ask"',
'buy': 'data.side == "Bid"'
Expand Down Expand Up @@ -165,20 +181,25 @@ export class OrdersComponent {
if ($event.event.target.getAttribute('data-action-type') != 'remove') return;
this.fireCxl.fire(new Models.OrderCancelRequestFromUI($event.data.orderId, $event.data.exchange));
};

private onCellValueChanged = ($event: CellValueChangedEvent) => {
this.editCxl.fire(new Models.OrderEditRequestFromUI(
$event.data.orderId,
parseFloat($event.data.price),
$event.data.quantity,
$event.data.side,
$event.data.symbol
));
};

private addAskBid = () => {
if (!this.filter || !this._markets) return;
loops: for (let x in this._markets)
for (let z in this._markets[x])
if (this.filter == this._markets[x][z].symbol) {
var ask = this._markets[x][z].ask;
var bid = this._markets[x][z].bid;
var len = Math.max(
(ask+'').indexOf('.') != -1 ? (ask+'').split('.')[1].length : 0,
(bid+'').indexOf('.') != -1 ? (bid+'').split('.')[1].length : 0
);
this.best_ask = ask.toFixed(len);
this.best_bid = bid.toFixed(len);
var precision = this.symbols.filter(s => s.symbol == this.filter)[0].pricePrecision;
this.best_ask = this._markets[x][z].ask.toFixed(precision);
this.best_bid = this._markets[x][z].bid.toFixed(precision);
this.orders_market = this._markets[x][z].web;
Shared.currencyHeaders(this.api, this._markets[x][z].base, this._markets[x][z].quote);
break loops;
Expand Down Expand Up @@ -212,19 +233,21 @@ export class OrdersComponent {
orderId: o.orderId,
exchangeId: o.exchangeId,
side: Models.Side[o.side],
price: o.price, //.toFixed(this.product.tickPrice)
value: (Math.round(o.quantity * o.price * 100) / 100), //.toFixed(this.product.tickPrice)
price: o.price.toFixed(-Math.log10(o.pricePrecision)),
value: o.quantity * o.price,
type: Models.OrderType[o.type],
tif: Models.TimeInForce[o.timeInForce],
lat: o.latency < 0 ? 'loaded' : o.latency + 'ms',
quantity: o.quantity, //.toFixed(this.product.tickSize)
quantity: o.quantity,
pong: o.isPong,
time: o.time
time: o.time,
pricePrecision: -Math.log10(o.pricePrecision),
quantityPrecision: -Math.log10(o.quantityPrecision)
});

remove = remove.filter(x => x.exchangeId != o.exchangeId);

this.addSymbol(o.symbol, o.side);
this.addSymbol(o.symbol, o.side, -Math.log10(o.pricePrecision));
});

this.api.applyTransaction({add, update, remove});
Expand All @@ -234,10 +257,11 @@ export class OrdersComponent {
}
};

private addSymbol(sym: string, side: Models.Side) {
private addSymbol(sym: string, side: Models.Side, pricePrecision: number) {
if (!this.symbols.filter(s => s.symbol == sym).length) {
this.symbols.push({
symbol: sym,
pricePrecision: pricePrecision,
bids: 0,
asks: 0
});
Expand Down
40 changes: 37 additions & 3 deletions src/bin/+portfolios/+portfolios.data.h
Original file line number Diff line number Diff line change
Expand Up @@ -384,18 +384,51 @@ namespace analpaper {
, K(bot)
{};
void click(const json &j) override {
if ((j.is_object() and !j.value("orderId", "").empty()))
if (j.is_object() and !j.value("orderId", "").empty())
K.clicked(this, j.at("orderId").get<string>());
};
mMatter about() const override {
return mMatter::CancelOrder;
};
};
struct InputEditOrder: public Client::Clickable {
private_ref:
const KryptoNinja &K;
ButtonCancelOrder &cancel;
public:
InputEditOrder(const KryptoNinja &bot, ButtonCancelOrder &c)
: Clickable(bot)
, K(bot)
, cancel(c)
{};
void click(const json &j) override {
cancel.click(j);
if (j.is_object()
and !j.value("symbol", "").empty()
and !j.value("side", "").empty()
and j.value("price", 0.0)
and j.value("quantity", 0.0)
) K.clicked(this, Order(
j.value("symbol", ""),
j.value("side", "") == "Bid" ? Side::Bid : Side::Ask,
j.value("price", 0.0),
j.value("quantity", 0.0),
Tstamp,
false,
K.gateway->randId()
));
};
mMatter about() const override {
return mMatter::EditOrder;
};
};

struct Buttons {
ButtonCancelOrder cancel;
ButtonCancelOrder cancel;
InputEditOrder edit;
Buttons(const KryptoNinja &bot)
: cancel(bot)
, edit(bot, cancel)
{};
};

Expand All @@ -407,7 +440,8 @@ namespace analpaper {
public:
Broker(const KryptoNinja &bot, const Buttons &b)
: Clicked(bot, {
{&b.cancel, [&](const json &j) { K.cancel(j); }}
{&b.cancel, [&](const json &j) { K.cancel(j); }},
{&b.edit, [&](const Order &o) { K.place(o); }}
})
, memory(bot)
, semaphore(bot)
Expand Down
5 changes: 3 additions & 2 deletions src/bin/trading-bot/trading-bot.data.h
Original file line number Diff line number Diff line change
Expand Up @@ -998,6 +998,7 @@ namespace tribeca {
if (j.is_object() and j.value("price", 0.0) and j.value("quantity", 0.0)) {
json order = j;
order["manual"] = true;
order["symbol"] = K.gateway->symbol;
order["orderId"] = K.gateway->randId();
K.clicked(this, order);
}
Expand All @@ -1015,7 +1016,7 @@ namespace tribeca {
, K(bot)
{};
void click(const json &j) override {
if ((j.is_object() and !j.value("orderId", "").empty()))
if (j.is_object() and !j.value("orderId", "").empty())
K.clicked(this, j.at("orderId").get<string>());
};
mMatter about() const override {
Expand Down Expand Up @@ -1076,7 +1077,7 @@ namespace tribeca {
, K(bot)
{};
void click(const json &j) override {
if ((j.is_object() and !j.value("tradeId", "").empty()))
if (j.is_object() and !j.value("tradeId", "").empty())
K.clicked(this, j.at("tradeId").get<string>());
};
mMatter about() const override {
Expand Down
Loading

0 comments on commit fea4795

Please sign in to comment.