Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
1aef48e
Added the code necessary to use a single ws to deliver many updates.
gemmell Feb 3, 2018
82387c2
Removed code I accidentally merged in.
gemmell Feb 3, 2018
7910741
Fix filter detection and mapping
Feb 4, 2018
10d17df
Update documentation
Feb 4, 2018
89fb21c
Version 2.5.0
Feb 4, 2018
e32dc21
Merge branch 'combined-ws-streams'
gemmell Feb 5, 2018
0865ede
Fixed price filter
gemmell Feb 6, 2018
07f4ba3
merged
gemmell Feb 6, 2018
d8a7af6
Added raw trade stream
gemmell Feb 6, 2018
96d9531
Added export.
gemmell Feb 7, 2018
fcfd3c7
Needs to be RawTradeUpdate
gemmell Feb 7, 2018
9ef4ef1
Added missing field and fixed the float/string thing.
gemmell Feb 16, 2018
2b67fe1
Added missing getters
gemmell Feb 16, 2018
d05a4be
Update to my own version of websocket-heartbeats
gemmell Feb 27, 2018
42dad3a
So much easier.
gemmell Feb 27, 2018
29b28cd
Need to parse floats
gemmell Apr 20, 2018
8d90f75
Added the parseFloat to the relevant structures.
gemmell Apr 21, 2018
431361f
Go through and parseFloat as needed.
gemmell Apr 30, 2018
16da175
OrderResult price should be a number.
gemmell Apr 30, 2018
383025f
In fact quantities should be numbers too.
gemmell Apr 30, 2018
126f094
Merged from master
gemmell Jul 10, 2019
80e1c89
Binance expects a string for the price
gemmell Jul 10, 2019
58ec04c
Added print out
gemmell Jul 16, 2019
78c553f
Added print out
gemmell Jul 16, 2019
2c3e79b
Added print out
gemmell Jul 16, 2019
eb3e0d7
Use the string version so we don't end up sending 1.1e-8
gemmell Jul 17, 2019
91ff5e0
Don't toFixed on the stopprice cuz I don't use it
gemmell Jul 18, 2019
27a71cf
Remove debug statement that allowed me to track down errors
gemmell Jul 19, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,6 @@ export { Ticker } from "./src/models/ticker/Ticker";
export { TickerStatistics } from "./src/models/ticker/TickerStatistics";
export { Trade } from "./src/models/trade/Trade";
export { TradeUpdate } from "./src/models/websocket/trade/TradeUpdate";
export { RawTradeUpdate } from "./src/models/websocket/trade/RawTradeUpdate";

export { BinanceApiClient } from "./src/BinanceApiClient";
179 changes: 177 additions & 2 deletions src/BinanceApiClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import * as WebSocket from "ws";
import { OrderBookUpdate } from "./models/websocket/depth/OrderBookUpdate";
import { CandlestickUpdate } from "./models/websocket/candlestick/CandlestickUpdate";
import { TradeUpdate } from "./models/websocket/trade/TradeUpdate";
import { RawTradeUpdate } from "./models/websocket/trade/RawTradeUpdate";
import { AccountUpdate } from "./models/websocket/account/AccountUpdate";
import { OrderUpdate } from "./models/websocket/order/OrderUpdate";
import { ExchangeInfo } from "./models/misc/ExchangeInfo";
Expand All @@ -39,6 +40,7 @@ import { HeartbeatHandler } from "websocket-heartbeats";
*/
export class BinanceApiClient {

private static readonly COMBINED_WS_BASE_URL: string = "wss://stream.binance.com:9443/stream?streams=";
private static readonly WS_BASE_URL: string = "wss://stream.binance.com:9443/ws/";
private static readonly DEFAULT_WS_TIMEOUT: number = 60000;

Expand Down Expand Up @@ -257,6 +259,9 @@ export class BinanceApiClient {
icebergQuantity?: number,
responseType?: ResponseType ): Promise< OrderAcknowledgement | OrderResult | OrderFull > {


const priceAsString: string = price.toFixed(8);
console.log("BinanceApiClient says the price is" + priceAsString);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd remove this console.log

let jsonResponse: any = await this.makeRequest(
HttpMethod.POST,
ApiVersion.V3,
Expand All @@ -272,7 +277,7 @@ export class BinanceApiClient {
[ "quantity", quantity ],
[
"price",
type === OrderType.MARKET || type === OrderType.STOP_LOSS ? null : price
(type === OrderType.MARKET || type === OrderType.STOP_LOSS) ? null : priceAsString
],
[ "newClientOrderId", clientOrderId ],
[ "stopPrice", stopPrice ],
Expand Down Expand Up @@ -587,6 +592,49 @@ export class BinanceApiClient {

}

/**
* Initializes a web socket data stream that gives us information about a combined
* stream of an array of symbol's order book updates.
*
* @param symbols The symbols of which we want to get the order book updates.
* @param onUpdate A function to be called when a new update is received.
* @param connectionTimeout Timeout based on which the web socket connection is
* considered to be broken based on a heartbeat monitor.
* @param onLostConnection A callback to be invoked when the web socket connection
* is detected as broken.
*/
public monitorOrderBookCombined(
symbol: string[],
onUpdate: ( update: OrderBookUpdate ) => any,
connectionTimeout: number,
onLostConnection: () => any ): void {

let url: string = "";
url = BinanceApiClient.COMBINED_WS_BASE_URL;
for ( let s of symbol ) {
url += s.toLowerCase() + "@depth" + "/";
}
// Trim the final slash
url.slice( 0, -1 );
const websocket: WebSocket = new WebSocket(
url,
{ perMessageDeflate: false }
);

new HeartbeatHandler(
websocket,
isNullOrUndefined( connectionTimeout ) ? BinanceApiClient.DEFAULT_WS_TIMEOUT : connectionTimeout,
onLostConnection
).handle();

websocket.on( "message", ( data: any ) => {
// For a combined stream the data is wrapped in an object with the
// streamname and the raw data.
const rawData = JSON.parse( data );
onUpdate( new OrderBookUpdate( rawData.data ) );
} );

}
/**
* Initializes a web socket data stream that gives us information about a
* single symbol's order book updates. Stream keepalive is performed through
Expand Down Expand Up @@ -625,6 +673,50 @@ export class BinanceApiClient {

/**
* Initializes a web socket data stream that gives us information about
* Kline/candlestick updates for a number of symbols on the one socket.
*
* @param symbols The symbols of which we want to get the candlestick updates.
* @param interval The interval to which the requested candlestick updates
* refer to.
* @param onUpdate A function to be called when a new update is received.
* @param connectionTimeout Timeout based on which the web socket connection is
* considered to be broken based on a heartbeat monitor.
* @param onLostConnection A callback to be invoked when the web socket connection
* is detected as broken.
*/
public async monitorCandlesticksCombined(
symbols: string[],
interval: CandlestickInterval,
onUpdate: ( update: CandlestickUpdate ) => any,
connectionTimeout?: number,
onLostConnection?: () => any ): Promise< void > {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd remove the spaces in the diamond notation here. And it's my bad, I should add a linter to the project.


let url: string = "";
url = BinanceApiClient.COMBINED_WS_BASE_URL;
for ( let s of symbols ) {
url += s.toLowerCase() + "@kline_" + interval + "/";
}
// Trim the final slash
url.slice( 0, -1 );
const websocket: WebSocket = new WebSocket(
url,
{ perMessageDeflate: false }
);

new HeartbeatHandler(
websocket,
isNullOrUndefined( connectionTimeout ) ? BinanceApiClient.DEFAULT_WS_TIMEOUT : connectionTimeout,
onLostConnection
).handle();

websocket.on( "message", ( data: any ) => {
const rawData = JSON.parse( data );
onUpdate( new CandlestickUpdate( rawData.data ) );
} );

}

/**
* Kline/candlestick updates. Stream keepalive is performed through
* [[keepAliveUserStream]] following the rules described
* [here](https://github.com/binance-exchange/binance-official-api-docs/blob/master/web-socket-streams.md)
Expand Down Expand Up @@ -662,6 +754,89 @@ export class BinanceApiClient {

}


/**
* Initializes a web socket data stream that gives us information about
* trade updates for a number of symbols on the one socket.
*
* @param symbols The symbols of which we want to get the trade updates.
* @param onUpdate A function to be called when a new update is received.
* @param connectionTimeout Timeout based on which the web socket connection is
* considered to be broken based on a heartbeat monitor.
* @param onLostConnection A callback to be invoked when the web socket connection
* is detected as broken.
*/
public monitorRawTradesCombined(
symbols: string[],
onUpdate: ( update: RawTradeUpdate ) => any,
connectionTimeout: number,
onLostConnection: () => any ): void {
let url: string = "";
url = BinanceApiClient.COMBINED_WS_BASE_URL;
for ( let s of symbols ) {
url += s.toLowerCase() + "@trade" + "/";
}
// Trim the final slash
url.slice( 0, -1 );
const websocket: WebSocket = new WebSocket(
url,
{ perMessageDeflate: false }
);

new HeartbeatHandler(
websocket,
isNullOrUndefined( connectionTimeout ) ? BinanceApiClient.DEFAULT_WS_TIMEOUT : connectionTimeout,
onLostConnection
).handle();

websocket.on( "message", ( data: any ) => {
const rawData = JSON.parse( data );
onUpdate( new RawTradeUpdate( rawData.data ) );
} );

}

/**
* Initializes a web socket data stream that gives us information about
* trade updates for a number of symbols on the one socket.
*
* @param symbols The symbols of which we want to get the trade updates.
* @param onUpdate A function to be called when a new update is received.
* @param connectionTimeout Timeout based on which the web socket connection is
* considered to be broken based on a heartbeat monitor.
* @param onLostConnection A callback to be invoked when the web socket connection
* is detected as broken.
*/
public monitorTradesCombined(
symbols: string[],
onUpdate: ( update: TradeUpdate ) => any,
connectionTimeout: number,
onLostConnection: () => any ): void {
let url: string = "";
url = BinanceApiClient.COMBINED_WS_BASE_URL;
for ( let s of symbols ) {
url += s.toLowerCase() + "@aggTrade" + "/";
}
// Trim the final slash
url.slice( 0, -1 );
const websocket: WebSocket = new WebSocket(
url,
{ perMessageDeflate: false }
);

new HeartbeatHandler(
websocket,
isNullOrUndefined( connectionTimeout ) ? BinanceApiClient.DEFAULT_WS_TIMEOUT : connectionTimeout,
onLostConnection
).handle();

websocket.on( "message", ( data: any ) => {
const rawData = JSON.parse( data );
onUpdate( new TradeUpdate( rawData.data ) );
} );

}

/**
* Initializes a web socket data stream that gives us information about
* trade updates. Stream keepalive is performed through
Expand Down Expand Up @@ -790,7 +965,7 @@ export class BinanceApiClient {
this.setupAuthentication( httpMethod, apiUrl, requiredAuthentication );

try {

return await request( {

method: HttpMethod[ httpMethod ],
Expand Down
4 changes: 2 additions & 2 deletions src/models/account/Balance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ export class Balance {
constructor( json: any ) {

this._asset = json.asset || json.a;
this._available = json.free || json.available || json.f;
this._locked = json.locked || json.l;
this._available = parseFloat(json.free || json.available || json.f);
this._locked = parseFloat(json.locked || json.l);

}

Expand Down
16 changes: 8 additions & 8 deletions src/models/candlestick/Candlestick.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,16 @@ export class Candlestick {
constructor( json: any ) {

this._openingTime = new Date( json[ 0 ] );
this._openingPrice = json[ 1 ];
this._highestPrice = json[ 2 ];
this._lowestPrice = json[ 3 ];
this._closurePrice = json[ 4 ];
this._baseAssetVolume = json[ 5 ];
this._openingPrice = parseFloat(json[ 1 ]);
this._highestPrice = parseFloat(json[ 2 ]);
this._lowestPrice = parseFloat(json[ 3 ]);
this._closurePrice = parseFloat(json[ 4 ]);
this._baseAssetVolume = parseFloat(json[ 5 ]);
this._closureTime = new Date( json[ 6 ] );
this._quoteAssetVolume = json[ 7 ];
this._quoteAssetVolume = parseFloat(json[ 7 ]);
this._tradesCount = json[ 8 ];
this._boughtBaseAssetVolume = json[ 9 ];
this._boughtQuoteAssetVolume = json[ 10 ];
this._boughtBaseAssetVolume = parseFloat(json[ 9 ]);
this._boughtQuoteAssetVolume = parseFloat(json[ 10 ]);

}

Expand Down
2 changes: 1 addition & 1 deletion src/models/depth/LatestPrice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export class LatestPrice {

constructor( json: any ) {
this._symbol = json.symbol;
this._price = json.price;
this._price = parseFloat(json.price);
}

get symbol(): string {
Expand Down
6 changes: 3 additions & 3 deletions src/models/filter/LotSizeFilter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ export class LotSizeFilter implements SymbolFilter {

constructor( json: any ) {

this._minimumQuantity = json.minQty;
this._maximumQuantity = json.maxQty;
this._stepSize = json.stepSize;
this._minimumQuantity = parseFloat(json.minQty);
this._maximumQuantity = parseFloat(json.maxQty);
this._stepSize = parseFloat(json.stepSize);

}

Expand Down
2 changes: 1 addition & 1 deletion src/models/filter/MinimumNotionalFilter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export class MinimumNotionalFilter implements SymbolFilter {
private _value: number;

constructor( json: any ) {
this._value = json.minNotional;
this._value = parseFloat(json.minNotional);
}

get value(): number {
Expand Down
6 changes: 3 additions & 3 deletions src/models/filter/PriceFilter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ export class PriceFilter implements SymbolFilter {

constructor( json: any ) {

this._minimumPrice = json.minPrice;
this._maximumPrice = json.maxPrice;
this._tickSize = json.tickSize;
this._minimumPrice = parseFloat(json.minPrice);
this._maximumPrice = parseFloat(json.maxPrice);
this._tickSize = parseFloat(json.tickSize);

}

Expand Down
10 changes: 5 additions & 5 deletions src/models/order/Order.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,15 @@ export class Order {
this._symbol = json.symbol;
this._id = json.orderId;
this._clientId = json.clientOrderId;
this._price = json.price;
this._originalQuantity = json.origQty;
this._executedQuantity = json.executedQty;
this._price = parseFloat(json.price);
this._originalQuantity = parseFloat(json.origQty);
this._executedQuantity = parseFloat(json.executedQty);
this._status = OrderStatus[ json.status as keyof typeof OrderStatus ];
this._timeInForce = TimeInForce[ json.timeInForce as keyof typeof TimeInForce ];
this._type = OrderType[ json.type as keyof typeof OrderType ];
this._side = OrderSide[ json.side as keyof typeof OrderSide ];
this._stopPrice = json.stopPrice;
this._icebergQuantity = json.icebergQty;
this._stopPrice = parseFloat(json.stopPrice);
this._icebergQuantity = parseFloat(json.icebergQty);
this._timestamp = new Date( json.time );

}
Expand Down
Loading