@ex-master/core
Advanced tools
Comparing version 0.1.34 to 0.1.35
import { Decimal } from 'decimal.js'; | ||
import { AccountData, ActiveOrder, Market, MarketData, Order, OrderType } from '../exchange'; | ||
import { AccountBalance, ActiveOrder, Market, MarketData, Order, OrderType } from '../exchange'; | ||
export declare const CLIENT_DEPTH_REPLAY = 10; | ||
@@ -13,12 +13,12 @@ export declare const CLIENT_TRADE_REPLAY = 100; | ||
readonly power: number; | ||
abstract getAccountData(): Promise<AccountData>; | ||
/** | ||
* This method is for canceling all active orders upon program start. | ||
*/ | ||
abstract cancelActiveOrders(): Promise<void>; | ||
abstract getAccountBalance(): Promise<Dict<AccountBalance>>; | ||
abstract getMarkets(): Promise<MarketData[]>; | ||
abstract getInactiveOrdersIn(orders: ActiveOrder[]): Promise<Order[]>; | ||
abstract order(market: Market, type: OrderType, price: Decimal, size: Decimal): Promise<string | undefined>; | ||
abstract cancelOrder(order: ActiveOrder): Promise<void>; | ||
abstract getOrder(order: ActiveOrder): Promise<Order>; | ||
/** | ||
* This method is for canceling all active orders upon program start. | ||
*/ | ||
abstract cancelActiveOrders(): Promise<void>; | ||
getUpdatedOrders(orders: ActiveOrder[]): Promise<Order[]>; | ||
cancelOrders(orders: ActiveOrder[]): Promise<void>; | ||
@@ -25,0 +25,0 @@ /** |
@@ -21,5 +21,2 @@ "use strict"; | ||
} | ||
getUpdatedOrders(orders) { | ||
return v.map(orders, async (order) => this.getOrder(order)); | ||
} | ||
async cancelOrders(orders) { | ||
@@ -26,0 +23,0 @@ await v.parallel(orders, async (order) => this.cancelOrder(order)); |
import { Decimal } from 'decimal.js'; | ||
import { BehaviorSubject } from 'rxjs'; | ||
import { BehaviorSubject, Observable } from 'rxjs'; | ||
import { Client } from '../client'; | ||
import { Dashboard } from '../dashboard'; | ||
import { Account } from './account'; | ||
import { AccountBalance } from './factors'; | ||
import { OrderDescriptor, OrderPaidFee, OrderType } from './order'; | ||
@@ -36,6 +36,10 @@ export declare type PrecisionAlignment = 'up' | 'down'; | ||
readonly dashboard: Dashboard; | ||
private balanceDict; | ||
private _balance$; | ||
readonly balance$: Observable<Dict<AccountBalance>>; | ||
readonly operationalBalance$: Observable<Dict<Decimal>>; | ||
readonly updating$: BehaviorSubject<boolean>; | ||
readonly account: Account; | ||
private activeOrderMap; | ||
private groupToLockObjectMap; | ||
private tickLockObject; | ||
private stockMoneyToMarketDataMap; | ||
@@ -47,3 +51,3 @@ private _markets; | ||
initialize(): Promise<void>; | ||
assertBalanceEfficiency(keys?: string[]): Promise<void>; | ||
getBalance(key: string): AccountBalance; | ||
getActiveOrders(group?: string): ActiveOrder[]; | ||
@@ -67,6 +71,4 @@ tick(): Promise<void>; | ||
private cancelOrders(orders); | ||
private removeInactiveOrder({id}); | ||
private cancelActiveOrders(); | ||
private updateAccountData(); | ||
private updateMarkets(); | ||
} |
@@ -8,3 +8,3 @@ "use strict"; | ||
const v = require("villa"); | ||
const account_1 = require("./account"); | ||
const object_1 = require("../util/object"); | ||
const debug = Debug('ex-master:core:exchange'); | ||
@@ -15,6 +15,21 @@ class Exchange { | ||
this.dashboard = dashboard; | ||
this._balance$ = new rxjs_1.ReplaySubject(1); | ||
this.balance$ = this._balance$ | ||
.debounce(() => rxjs_1.Observable.empty()) | ||
.distinctUntilChanged(object_1.isEqual) | ||
.shareReplay(1); | ||
this.operationalBalance$ = this.balance$ | ||
.map((balanceDict) => { | ||
return Object.keys(balanceDict).reduce((dict, key) => { | ||
let { available, frozen } = balanceDict[key]; | ||
dict[key] = available.add(frozen); | ||
return dict; | ||
}, {}); | ||
}) | ||
.distinctUntilChanged(object_1.isEqual) | ||
.shareReplay(1); | ||
this.updating$ = new rxjs_1.BehaviorSubject(false); | ||
this.account = new account_1.Account(this.dashboard); | ||
this.activeOrderMap = new Map(); | ||
this.groupToLockObjectMap = new Map(); | ||
this.tickLockObject = {}; | ||
this.stockMoneyToMarketDataMap = new multikey_map_1.MultikeyMap(); | ||
@@ -29,18 +44,9 @@ this.pendingUpdatesPriorityScale = pendingUpdatesPriorityScale; | ||
await this.cancelActiveOrders(); | ||
await this.updateAccountData(); | ||
await this.tick(); | ||
} | ||
async assertBalanceEfficiency(keys) { | ||
let { balance: balanceDict } = await this.client.getAccountData(); | ||
if (!keys) { | ||
keys = Object.keys(balanceDict); | ||
} | ||
for (let key of keys) { | ||
let { available, frozen } = balanceDict[key]; | ||
let { available: calculatedAvailable, frozen: calculatedFrozen, } = this.account.getBalance(key); | ||
let latest = available.add(decimal_js_1.Decimal.min(frozen, calculatedFrozen)); | ||
let calculated = calculatedAvailable.add(calculatedFrozen); | ||
if (latest.dividedBy(calculated).greaterThan(1.0001)) { | ||
throw new Error(`Balance efficiency assertion failure on "${key}" (${latest} <-> ${calculated})`); | ||
} | ||
} | ||
getBalance(key) { | ||
return (this.balanceDict[key] || { | ||
available: new decimal_js_1.Decimal(0), | ||
frozen: new decimal_js_1.Decimal(0), | ||
}); | ||
} | ||
@@ -59,9 +65,15 @@ getActiveOrders(group) { | ||
} | ||
let orders = await this.client.getUpdatedOrders(activeOrders); | ||
for (let order of orders) { | ||
this.account.onOrderUpdate(order); | ||
if (!order.active) { | ||
this.removeInactiveOrder(order); | ||
await v.lock(this.tickLockObject, async () => { | ||
let canceledOrders = await this.client.getInactiveOrdersIn(activeOrders); | ||
let balanceDict = await this.client.getAccountBalance(); | ||
this.balanceDict = balanceDict; | ||
this._balance$.next(balanceDict); | ||
for (let { id } of canceledOrders) { | ||
let activeOrder = this.activeOrderMap.get(id); | ||
if (activeOrder) { | ||
activeOrder.becomeInactiveResolver(); | ||
} | ||
this.activeOrderMap.delete(id); | ||
} | ||
} | ||
}); | ||
} | ||
@@ -258,3 +270,3 @@ async updateOrders(group, descriptors) { | ||
let value = price.mul(size); | ||
let available = this.account.getBalance(market.money).available; | ||
let available = this.getBalance(market.money).available; | ||
if (available.lessThan(value)) { | ||
@@ -265,3 +277,3 @@ size = this.ensureSizePrecision(market, available.dividedBy(price)); | ||
else { | ||
let available = this.account.getBalance(market.stock).available; | ||
let available = this.getBalance(market.stock).available; | ||
if (available.lessThan(size)) { | ||
@@ -285,3 +297,3 @@ size = this.ensureSizePrecision(market, available); | ||
let key = type === 'ask' ? market.stock : market.money; | ||
return this.account.getBalance(key).available.greaterThanOrEqualTo(target); | ||
return this.getBalance(key).available.greaterThanOrEqualTo(target); | ||
} | ||
@@ -307,3 +319,2 @@ async order(group, { market, label, type, price, size, priority, asap }) { | ||
}; | ||
this.account.onOrderCreate(order); | ||
let { active: _active, ...orderExtra } = order; | ||
@@ -344,9 +355,2 @@ let becomeInactiveResolver; | ||
} | ||
removeInactiveOrder({ id }) { | ||
let activeOrder = this.activeOrderMap.get(id); | ||
if (activeOrder) { | ||
activeOrder.becomeInactiveResolver(); | ||
} | ||
this.activeOrderMap.delete(id); | ||
} | ||
async cancelActiveOrders() { | ||
@@ -356,7 +360,2 @@ this.dashboard.info('cancel active orders...'); | ||
} | ||
async updateAccountData() { | ||
this.dashboard.info('update account data...'); | ||
let { balance } = await this.client.getAccountData(); | ||
this.account.initializeBalance(balance); | ||
} | ||
async updateMarkets() { | ||
@@ -363,0 +362,0 @@ this.dashboard.info('update markets...'); |
@@ -7,5 +7,2 @@ import { Decimal } from 'decimal.js'; | ||
} | ||
export interface AccountData { | ||
balance: Dict<AccountBalance>; | ||
} | ||
export interface MarketPrecision { | ||
@@ -12,0 +9,0 @@ size: number; |
@@ -1,4 +0,3 @@ | ||
export * from './account'; | ||
export * from './exchange'; | ||
export * from './order'; | ||
export * from './factors'; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const tslib_1 = require("tslib"); | ||
tslib_1.__exportStar(require("./account"), exports); | ||
tslib_1.__exportStar(require("./exchange"), exports); | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "@ex-master/core", | ||
"version": "0.1.34", | ||
"version": "0.1.35", | ||
"main": "bld/index.js", | ||
@@ -5,0 +5,0 @@ "types": "bld/index.d.ts", |
54494
34
1551