When creating a limit order on Binance, especially while adding take profit/stop loss percentages or calculating quantity, it's mandatory to round the price and quantity based on the filters available in the exchange information API endpoint. Otherwise the create limit order endpoint would fail. This is detailed in the following article: https://sammchardy.github.io/binance-order-filters/.
My concern is with the implementation of rounding. For instance, the ClampPrice method in the Binance.Net library (https://github.com/JKorf/Binance.Net/blob/master/Binance.Net/BinanceHelpers.cs) seems to just apply a basic min-max approach, which doesn't appear entirely accurate to me.
I made an extension method that in my opinion is more correct. For prices, I round based on the tick size (BinanceSymbolPriceFilter.TickSize), and for quantities, I use the step size (BinanceSymbolLotSizeFilter.StepSize).
public static class BinanceHelpers
{
public static decimal RoundStepSize(decimal priceOrQuantity, decimal stepSize) => priceOrQuantity - priceOrQuantity % stepSize;
}
I need to confirm the correctness or completeness of my approach from a trustworthy source, such as the official Binance API documentation.
Here are the filters for BTC/USDT that the exchange information endpoint returns:
Filters = {BinanceSymbolFilter[]} BinanceSymbolFilter[9]
[0] = BinanceSymbolPriceFilter
FilterType = {SymbolFilterType} Price
MaxPrice = {Decimal} 1000000.00000000
MinPrice = {Decimal} 0.01000000
TickSize = {Decimal} 0.01000000
[1] = BinanceSymbolLotSizeFilter
FilterType = {SymbolFilterType} LotSize
MaxQuantity = {Decimal} 9000.00000000
MinQuantity = {Decimal} 0.00001000
StepSize = {Decimal} 0.00001000
[2] = BinanceSymbolIcebergPartsFilter
FilterType = {SymbolFilterType} IcebergParts
Limit = {int} 10
[3] = BinanceSymbolMarketLotSizeFilter
FilterType = {SymbolFilterType} MarketLotSize
MaxQuantity = {Decimal} 114.12693879
MinQuantity = {Decimal} 0.00000000
StepSize = {Decimal} 0.00000000
[4] = BinanceSymbolTrailingDeltaFilter
FilterType = {SymbolFilterType} TrailingDelta
MaxTrailingAboveDelta = {int} 2000
MaxTrailingBelowDelta = {int} 2000
MinTrailingAboveDelta = {int} 10
MinTrailingBelowDelta = {int} 10
[5] = BinanceSymbolPercentPriceBySideFilter
AskMultiplierDown = {Decimal} 0.2
AskMultiplierUp = {Decimal} 5
AveragePriceMinutes = {int} 5
BidMultiplierDown = {Decimal} 0.2
BidMultiplierUp = {Decimal} 5
FilterType = {SymbolFilterType} PercentagePriceBySide
[6] = BinanceSymbolNotionalFilter
ApplyMaxToMarketOrders = {bool} false
ApplyMinToMarketOrders = {bool} true
AveragePriceMinutes = {int} 5
FilterType = {SymbolFilterType} Notional
MaxNotional = {Decimal} 9000000.00000000
MinNotional = {Decimal} 5.00000000
[7] = BinanceSymbolMaxOrdersFilter
FilterType = {SymbolFilterType} MaxNumberOrders
MaxNumberOrders = {int} 200
[8] = BinanceSymbolMaxAlgorithmicOrdersFilter
FilterType = {SymbolFilterType} MaxNumberAlgorithmicOrders
MaxNumberAlgorithmicOrders = {int} 5