I was trying to solve the problem But I could not figure it out.
I have product dictionary:
product = {
"shirt" : {
"price" :300 ,
"no_reqired_for_dis" : {"3": ["shirt","pents","tshirt","shorts"],"discount_price" : 250}},
"pents" : {
"price" :200 ,
"no_reqired_for_dis" : {"3": ["shirt","pents","tshirt","shorts"],"discount_price" : 250}}
"tshirt" : {
"price" :150 ,
"no_reqired_for_dis" : {"3": ["shirt","pents","tshirt","shorts"],"discount_price" : 250}}
"shorts" : {
"price" :100 ,
"no_reqired_for_dis" : {"3": ["shirt","pents","tshirt","shorts"],"discount_price" : 250}}
}
What should be best approach to to find the total
discount criteria if anyone who buys a minimum of three products or a multiple of 3 they will get three item for 250?
for example if someone buy total 11 (shirt = 5,pants = 4, tshirt = 1, short = 1) products,then their total should be 250 * 3 + remaining item * lowest price product. Here remaining item should be lowest price of the product(here it should be shorts and tshirt).
I have done this:
total_payment = 0
total_product = {"shirt" : 5,"pents":4,"tshirt":1,"shorts" 1}
total_item = sum(total_product.values())
for key, value in total_product.items():
min_no_required_for_discount = product[key]["no_required_for_dis"].keys()
if total_item < int(min_no_required_for_discount[0]:
total_payment += value * product[key]["price"]
else:
remaining_unit = total_item % 3
total_pair = (total_item - remaining_unit) // 3
total_payment += total_pair * 250
Now i am confuse in remaining_unit. how to calculate price for remaining_unit because remaining_unit must multiply with who has minimum price . in above example remaining_unit will be 2 and it will calculate price of shorts and tshirt
Here is quick template that might help you to start working on this problem:
[Notes: use set() to get the items difference quickly, and use print() statement to confirm each step is expected] Again, this is NOT a complete solution - but just offers a good template for you to start quickly.
from pprint import pprint
lowest_price_items = ['tshirt', 'shorts']
discount_price_items = ['shirt', 'pants']
discount_Set = set(discount_price_items)
cart = ['shirt', 'shirt', 'shirt', 'shirt', 'shirt', 'pants', 'pants', 'pants', 'pants', 'tshirt', 'shorts']
cart_Set = set(cart)
low_price_goods = cart_Set - discount_Set
pprint(product)
print(f' products: {product.keys()} ') # first level of prod. dict.
print(product['shirt'].keys()) # 'price' and 'no_requied_for_dis'
# products key1 key2
print(product['shirt']['no_reqired_for_dis']['discount_price']) # 250
tshirt_price = product['tshirt']['price']
print(tshirt_price)
"""
total should be 250 * 3 + remaining item * lowest_price_products (tshirts, shorts) only
"""
total_items = len(cart)
print(total_items)
# modify this to calculate the final price.
if total_items > 3:
final_price = 250 * total_items %3 + "remaining item * lowest_price_products" # select the lowest price items
Related
I am triyng to build a strategy on tradingview which i want to automate after but i am stuck to
2 functions...
Inside the strategy is a simple buy after a red candle close(for close to 50% win rate) 1:1 risk ration reward, the thing is that the backtesting show a loss for a long period of time because it can catch 7 or 8 lossing trades in a row and blow up my account...
So i want to stop the strategy after EX: 7 losses in a row and start again after with multiplier 1 and double after as usual, but to stop after it lost the "x" loss in a row.
The 2nd thing it would be to enter a trade after 2 losses in a row, so in this way i could start after some losses and same here after "x" losses in a row Stop strategy and restart it.
I hope i explained as clear as possible...
I couldn't find anything about this 2 functions, i have to mention that i am new to pine code but still i manage to build this strategy after watching multiple startegys code...some code is barrowed.
Here is my full code :
//#version=5
strategy(title='Test martingale', overlay=true, slippage=15, initial_capital=1000, currency=currency.USD)
maxWinStreak = input.int(title="Max Winning Streak Length",
defval=7, minval=1)
newWin = (strategy.wintrades > strategy.wintrades[1]) and
(strategy.losstrades == strategy.losstrades[1]) and
(strategy.eventrades == strategy.eventrades[1])
// loss steak
maxLossStreak = input.int(title="Max Losing Streak Length",
defval=7, minval=1)
newLoss = (strategy.losstrades > strategy.losstrades[1]) and
(strategy.wintrades == strategy.wintrades[1]) and
(strategy.eventrades == strategy.eventrades[1])
// Figure out current winning streak length
streakLen = 0
streakLen := if (newWin)
nz(streakLen[1]) + 1
else
if (strategy.losstrades > strategy.losstrades[1]) or
(strategy.eventrades > strategy.eventrades[1])
0
else
nz(streakLen[1])
// Figure out current lossing streak length
streakLen2 = 0
streakLen2 := if (newLoss)
nz(streakLen2[1]) + 1
else
if (strategy.wintrades > strategy.wintrades[1]) or
(strategy.eventrades > strategy.eventrades[1])
0
else
nz(streakLen2[1])
//Max lossing streak
okToTrade1 = streakLen2 < maxLossStreak
//Max winning streak
okToTrade = streakLen < maxWinStreak
src = close
long = close < open
win_mult = input.float(defval=1.00, step=0.05, title='Multiplier for Winning Streak')
loss_mult = input.float(defval=2, step=0.05, title='Multiplier for Losing Streak')
//Just hedge the last trade
dir = 0.0
//Count the current streak of winning/losing trades
calcWinMult(mult) =>
result = 0.0
change_1 = ta.change(strategy.losstrades)
change_2 = ta.change(strategy.wintrades)
change_3 = ta.change(strategy.eventrades)
result := na(result[1]) ? 1 : change_1 > 0 ? 1 : change_2 > 0 or change_3 > 0 ? nz(result[1]) * mult : nz(result[1])
result
calcLossMult(mult) =>
result = 0.0
change_1 = ta.change(strategy.wintrades)
change_2 = ta.change(strategy.losstrades)
change_3 = ta.change(strategy.eventrades)
result := na(result[1]) ? 1 : change_1 > 0 ? 1 : change_2 > 0 or change_3 > 0 ? nz(result[1]) * mult : nz(result[1])
result
//Gett the type of trade we need
type = 0.0
change_1 = ta.change(strategy.losstrades)
type := ta.change(strategy.wintrades) > 0 ? 1 : change_1 > 0 ? -1 : nz(type[1], 1)
//Get the martingale multiplier for the nex trade
calcWinMult__1 = calcWinMult(win_mult)
calcLossMult__1 = calcLossMult(loss_mult)
qtyMult = type > 0 ? calcWinMult__1 : calcLossMult__1
//Basic buy/sell signals
buy = long
//Plot
red = color.red
green = color.lime
white = color.white
plotshape(long, text='buy', style=shape.labelup, location=location.belowbar,
color=color.new(green, 0), textcolor=color.new(white, 0))
lots = input(defval=1)
adjustedLots = 1 * qtyMult
if strategy.equity > strategy.initial_capital * 0.2 and strategy.closedtrades + strategy.opentrades < 5000 and okToTrade and okToTrade1
strategy.entry('LONG', strategy.long, qty=adjustedLots, when=buy)
strategy.exit('L.exit', from_entry='LONG', profit= 200, loss=200)
Thank you in advance for your help.
Here is the helper function calculates number of losses in a row. You can use it in your script for detect is the strategy can trade or not.
//#version=5
strategy("My strategy", overlay=true, margin_long=100, margin_short=100)
numberOfLossesInRow()=>
result = 0
if 0 != strategy.closedtrades
for i = strategy.closedtrades - 1 to 0
if strategy.closedtrades.profit(i) < 0
result += 1
else
break
result
lossesInRow = numberOfLossesInRow()
plot(lossesInRow)
canTrade = lossesInRow < 5
longCondition = ta.crossover(ta.sma(close, 14), ta.sma(close, 28))
if (longCondition and canTrade)
strategy.entry("My Long Entry Id", strategy.long)
shortCondition = ta.crossunder(ta.sma(close, 14), ta.sma(close, 28))
if (shortCondition and canTrade)
strategy.entry("My Short Entry Id", strategy.short)
I am creating a shopping cart application applying tax rate and showing the sum of items and total, I could get all the infos showing in the screen except the sum of all items with the taxRate applied. Clearly I'm missing something but I am not sure what I could do to populate price and tax rate for all products and sum them together.
cart = {"Shirt": ["Clothing", 39.99, "Manhattan"], "TV": ["Electronic", 999.00, "White Plains"], "Muffin": ["Bread", 9.50, "Manhattan"], "Jacket": ["Clothing", 45.95, "White Plains"], "Coat": ["Clothing", 239.55, "Manhattan"]}
for i in cart:
unit = cart[i][1]
city = cart[i][2]
kind = cart[i][0]
taxPercent = getTaxRate(city, kind, unit)
print ("*tax: ${:.2f}".format(taxPercent*unit), "\n{}:".format(i), unit,"+ ${:.2f}".format(taxPercent*unit),"= ${:.2f}".format(unit + taxPercent*unit))
# print ("--------- Please pay the following:------- \n", "Total:${:.2f}".format(items + taxPercent*items))
Output should be:
*Tax: 00.0
Shirt: $39.99
TV: 999.0+99.90 = $1098.90
*Tax: 99.90
Muffin: 9.5+0.95 = $10.45
*Tax: 0.95
Jacket: 45.95+4.14 = $50.09
*Tax: 4.14
Coat: 239.55+21.56 = $261.11
*Tax: 21.56
---------- Please pay the following ----------
Total: $1460.54
You have to add values to sum it up you can do it by adding statement in code
totalamt=totalamt+unit + taxPercent*unit
it will add the price by iterating loop
cart = {"Shirt": ["Clothing", 39.99, "Manhattan"], "TV": ["Electronic", 999.00, "White Plains"], "Muffin": ["Bread", 9.50, "Manhattan"], "Jacket": ["Clothing", 45.95, "White Plains"], "Coat": ["Clothing", 239.55, "Manhattan"]}
def getTaxRate (city, kind, price): # given call and simple return
if city == "Manhattan":
if kind == "Clothing":
if price > 100:
taxRate = 0.09
else:
taxRate = 0.0
elif kind == "Electronic":
taxRate = 0.11
else:
taxRate = 0.1
elif city == "White Plains":
if kind == "Electronic":
taxRate = 0.1
else:
taxRate = 0.09
return taxRate
totalamt=0
for k,v in cart.items():
# print(v)
unit = v[1]
city = v[2]
kind = v[0]
taxPercent = getTaxRate(city, kind, unit)
print("*tax: ${:.2f}".format(taxPercent*unit), "\n{}:".format(k), unit,"+ ${:.2f}".format(taxPercent*unit),"= ${:.2f}".format(unit + taxPercent*unit))
totalamt=totalamt+unit + taxPercent*unit
print("--------- Please pay the following:------- \n", "Total:${:.2f}".format(totalamt))
I am using PuLP to solve a minimization problem for a Loan optimisation problem. The code below is outputting the correct combination of loans with the current constraints (capital requirement and max drawdown amounts).
from pulp import *
class Loan():
def __init__(self, id, interest_rate, drawdown_amount, lender, min_drawdown, max_drawdown):
self.id = id
self.interest_rate = interest_rate
self.drawdown_amount = drawdown_amount
self.lender = lender
self.min_drawdown = min_drawdown
self.max_drawdown = max_drawdown
def __str__(self):
return f"loan(id={self.id}, lender={self.lender}, drawdown_amount={self.drawdown_amount}, interest_rate={self.interest_rate}, min_drawdown={self.min_drawdown}, max_drawdown={self.max_drawdown})"
# PROBLEM DATA:
capital_requirement = 1200000
ids = ["WF_1", "BA_1", "BA_2", "JP_1"]
interest_rates = [0.05, 0.03, 0.02, 0.04]
drawdown_amounts = [1,1,1,1,1]
lenders = ["Wells Fargo", "Bank of America" , "Bank of America", "JPMorgan"]
min_drawdowns = [75000, 100000, 300000, 80000]
max_drawdowns = [500000, 500000, 500000, 500000]
loans = [Loan(id, interest_rate, drawdown_amount, lender, min_drawdown, max_drawdown ) for id, interest_rate, drawdown_amount, lender, min_drawdown, max_drawdown in
zip(ids, interest_rates, drawdown_amounts, lenders, min_drawdowns, max_drawdowns)]
# DECLARE PROBLEM OBJECT
prob = LpProblem("Loan Optimiser", LpMinimize)
# VARIABLES
loanVars = LpVariable.dicts('loans', loans, 0)
# OBJECTIVE
prob += lpSum([loan.interest_rate * loanVars[loan] for loan in loans])
# CONSTRAINTS
# Amount of money to borrow:
prob += lpSum([loan.drawdown_amount * loanVars[loan] for loan in loans]) == capital_requirement
# If a loan is included, it must be below the maximum drawdown amount of that loan:
for loan in loans:
prob += loanVars[loan] <= loan.max_drawdown * loanVars_selected[loan]
Sample output with capital requirement of 1.2m:
---------The optimal loans to use for borrowing € 1200000.0 are----------
$200000.0 of JP_1
$500000.0 of BA_1
$500000.0 of BA_2
Total Interest Cost = $33000.00
Total Interest Rate = 2.75 %
I would like to add a constraint so that a lender can only appear once in the output, in the above example this would remove BA_1 from the output and add in WF_1.
The code that I have written for this constraint is below but is not applying the logic correctly:
unique_lenders = set([loan.lender for loan in loans])
print(unique_lenders)
for lender in unique_lenders:
prob += lpSum([loanVars[loan] for loan in loans if loan.lender == lender]) >= 1
Thanks in advance.
EDIT:
I got the constraint working using a binary variable loanVars_selected and the below code based off Erwins answer:
for lender in unique_lenders:
prob += lpSum(loanVars_selected[loan] for loan in loans if loan.lender == lender) <= 1
I think you want a binary variable for each loan. Then add:
loanVars[loan] <= b[loan]*maxLoan[loan]
and
for each lender L:
sum(for all loans issued by L,b[loan]) <= 1
(I used pseudo code for clarity)
import config
import robin_stocks as r
r.login(config.USERNAME,config.PASSWORD)
#specify criteria to search for options of a given symbol and its exp date
symbol = 'F'
expirationDate = '2020-06-19'
So the code searches for an option with the highest implied volatility.
search_option = r.find_options_for_stock_by_expiration(symbol,expirationDate,optionType='call')
#identify option with highest implied volatility
highest_IV, highest_idx = 0, None
for idx, option in enumerate(search_option):
if option['implied_volatility'] and highest_IV < float(option['implied_volatility']):
highest_IV = float(option['implied_volatility'])
highest_idx = idx
if highest_idx is not None:
print("Strike Price: {strike_price}, Ask: {ask_price}, Bid: {bid_price}, Delta: {delta}, IV: {implied_volatility}, Order ID: {id}".format(**search_option[highest_idx]))
It then gives me this output:
Strike Price: 1.5000, Ask: 4.900000, Bid: 4.800000, Delta: 0.990127, IV: 9.900301, Order ID: 08bd63f8-2716-4d0a-af09-b2980b933a20
My only problem is, how can I save this output into separate variables?
So it should look something like:
order_strike = 1.5000
order_ask = 4.900000
order_bid = 4.800000
.....
Note: strike, ask, bid, delta and implied volatility have to be integers but order ID has to be a string.
I tried tackling the problem by adding the following code:
order_strike = option.get('strike_price')
order_ask = option.get('ask_price')
order_bid = option.get('bid_price')
order_delta = option.get('delta')
order_IV = option.get('implied_volatility')
order_id = option.get('id')
print('Strike: ', order_strike)
print('Ask Price: ', order_ask)
....
....
But I got this output instead (which clearly does not match the output found in search_option, i.e, Strike: 1.500 etc.):
Strike: 17.0000
Ask Price: 0.010000
Bid Price: 0.000000
Delta: 0.012675
IV: 5.472782
ID: dbcccdb0-cbaa-49f7-b57d-df171bf1e9cf
Any ideas?
When trying to place a buy or sell order with the python-binance api I got the following error:
APIError(code=-1013): Filter failure: LOT_SIZE.
Now I've seen at iceberg_parts that this means there is probably something wrong with my buying or selling quantity. I've tried to increase the quantity by a factor 10 but this only gives me another related error:
APIError(code=-1013): Filter failure: MIN_NOTIONAL.
Here's some of my code:
diff = current_price - prev_price
if diff <= 0.0001:
order = client.order_market_buy(symbol = market , quantity = '0.0001')
print('buy order')
if diff >= 0.00040:
order = client.order_market_sell(symbol =market, quantity ='0.0001')
print('sell order')
Do you know how to fix this?
This error appears because you are trying to create an order with a quantity lower than the minimun required.
You can access the minimun required of a specific pair with:
info = client.get_symbol_info('ETHUSDT')
print(info)
Output a dictionary with information about that pair.
Now you can access the minimun quantity required with:
print(info['filters'][2]['minQty'])
# 0.00001
The buying or selling quantity has to be >= 10.3 USD or 10.3/price, pass the quantity and price to these decimal settings/filters with the amounts set with decimal
from decimal import Decimal as D, ROUND_DOWN, ROUND_UP
import decimal
info = client.get_symbol_info(symbol=pair)
price_filter = float(info['filters'][0]['tickSize'])
ticker = client.get_symbol_ticker(symbol=pair)
price = float(ticker['price'])
price = D.from_float(price).quantize(D(str(price_filter)))
minimum = float(info['filters'][2]['minQty']) # 'minQty'
quant = D.from_float(quantity).quantize(D(str(minimum))) # if quantity >= 10.3/price
I've just gone through this same problem. As a noob, some of the code in these answers seem quite complicated so I came up with a solution.
Code:
def check_decimals(symbol):
info = client.get_symbol_info(symbol)
val = info['filters'][2]['stepSize']
decimal = 0
is_dec = False
for c in val:
if is_dec is True:
decimal += 1
if c == '1':
break
if c == '.':
is_dec = True
return decimal
then when you place the order, just do for ex:
(make sure qty is a float or decimal)
B_order = round(qty / symbol_price, decimal)
order = client.order_market_buy(
symbol=symbol_name,
quantity=B_order)
Maybe this can explain why the server returns this error.
Filters
From the endpoint GET /api/v3/exchangeInfo, you can find all details regarding the trading symbols. It includes many filters that clients need to follow to place an order. For example, the BTCUSDT has the filters as of today(2022-08-31)
"filters": [
{
"filterType": "PRICE_FILTER",
"minPrice": "0.01000000",
"maxPrice": "1000000.00000000",
"tickSize": "0.01000000"
},
{
"filterType": "PERCENT_PRICE",
"multiplierUp": "5",
"multiplierDown": "0.2",
"avgPriceMins": 5
},
{
"filterType": "LOT_SIZE",
"minQty": "0.00001000",
"maxQty": "9000.00000000",
"stepSize": "0.00001000"
},
{
"filterType": "MIN_NOTIONAL",
"minNotional": "10.00000000",
"applyToMarket": true,
"avgPriceMins": 5
},
{
"filterType": "ICEBERG_PARTS",
"limit": 10
},
{
"filterType": "MARKET_LOT_SIZE",
"minQty": "0.00000000",
"maxQty": "282.39806510",
"stepSize": "0.00000000"
},
{
"filterType": "TRAILING_DELTA",
"minTrailingAboveDelta": 10,
"maxTrailingAboveDelta": 2000,
"minTrailingBelowDelta": 10,
"maxTrailingBelowDelta": 2000
},
{
"filterType": "MAX_NUM_ORDERS",
"maxNumOrders": 200
},
{
"filterType": "MAX_NUM_ALGO_ORDERS",
"maxNumAlgoOrders": 5
}
]
LOT_SIZE validation
minQty
If you place an order on this BTCUSDT with parameters:
price=19000
side=BUY
type=LIMIT
quantity=0.000005
that is a LIMIT BUY order with price of $19,000, but the quantity is less than minQty in the LOT_SIZE:
0.000005 < 0.00001000
then the server will reject the order, because the request can't pass this filter validation.
✗ LOT_SIZE.minQty
stepSize
Can I place an order with the same parameters but only change the quantity to 0.000015? That is:
price=19000
side=BUY
type=LIMIT
quantity=0.000015
You will still receive this error, because the quantity is not able to pass the stepSize size validation: (quantity- minQty) % stepSize == 0
(0.000015 - 0.00001) % 0.00001 != 0
✓ LOT_SIZE.minQty
✗ LOT_SIZE.stepSize
MIN_NOTIONAL Validation
Alright, let us change the quantity to 0.00002, with same parameters:
price=19000
side=BUY
type=LIMIT
quantity=0.00002
The order will still be rejected with a different error because it can't pass the filter MIN_NOTIONAL validation.
19000 x 0.00002 = 0.38 < 10 (MIN_NOTIONAL.minNotional)
Note:
minNotional defines the minimum notional value that required for each order.
For MARKET order, the average price is used over the last avgPriceMins minutes.
✓ LOT_SIZE.minQty
✓ LOT_SIZE.stepSize
✗ MIN_NOTIONAL.minNotional
Here is some code.
def round_down(self, coin, number):
info = self.client.get_symbol_info('%sUSDT' % coin)
step_size = [float(_['stepSize']) for _ in info['filters'] if _['filterType'] == 'LOT_SIZE'][0]
step_size = '%.8f' % step_size
step_size = step_size.rstrip('0')
decimals = len(step_size.split('.')[1])
return math.floor(number * 10 ** decimals) / 10 ** decimals
https://python-binance.readthedocs.io/en/latest/account.html
from binance.helpers import round_step_size
# to get a lot size
def getLotSize(self):
info = self.apiCall(lambda: self.client.get_symbol_info(self.pair))
lotSize = float(info['filters'][2]['minQty'])
return lotSize
# get ceiling value and correct format for a lot size
def getCeilingVal(self):
pairData = self.apiCall(lambda:
self.client.get_symbol_ticker(symbol=self.pair))
pairPrice = pairData["price"]
ceilingVal = float(self.dInv) / float(pairPrice)
aLotSize = self.getLotSize()
rounded_amount = round_step_size(ceilingVal, aLotSize)
return rounded_amount
Here's a very helpful code using binance-python package
...
// Full code: https://github.com/ndiecodes/binance-trading-bot/blob/main/main.py
def get_round_step_quantity(self, qty):
info = self.client.get_symbol_info(Config.TRADESYMBOL)
for x in info["filters"]:
if x["filterType"] == "LOT_SIZE":
self.minQty = float(x["minQty"])
self.maxQty = float(x["maxQty"])
self.stepSize= float(x["stepSize"])
if qty < self.minQty:
qty = self.minQty
return round_step_size(quantity=qty, step_size=self.stepSize)
I have read through all of these forum questions and no one has mentioned the fact that Binance charges a 0.1% fee on all transactions. Meaning you do not have your original buying quantity available to sell back when the sell is triggered.
I have attempted to solve this with:
buy_quantity = round(buy_amount * 0.999, len(str(lotsize).split('.')[1]))
Multiplying my original purchase quantity by 0.999 should reduce it by the amount needed to be able to sell it back.
Hi adding a bit further to #stack if I've 20 dollars to buy then my quantity would be as below
I've done like below
decimal_places=abs(Decimal(symbl_info['filters'][2]["stepSize"]).normalize().as_tuple().exponent)
print("DECIMAL PLACES {0}".format(decimal_places))
buy_qauntity= round((20/order_input["askPrice"].values[0]),decimal_places)
print(buy_qauntity)
I write a function like that. It's working for me.
def getPriceLotFormat(self, priceOrg, quantityOrg):
price = float(priceOrg)
quantity = float(quantityOrg)
response = self.get_symbol_info(car.pair) #self is client btw
priceFilterFloat = format(float(response["filters"][0]["tickSize"]), '.20f')
lotSizeFloat = format(float(response["filters"][2]["stepSize"]), '.20f')
# PriceFilter
numberAfterDot = str(priceFilterFloat.split(".")[1])
indexOfOne = numberAfterDot.find("1")
if indexOfOne == -1:
price = int(price)
else:
price = round(float(price), int(indexOfOne - 1))
# LotSize
numberAfterDotLot = str(lotSizeFloat.split(".")[1])
indexOfOneLot = numberAfterDotLot.find("1")
if indexOfOneLot == -1:
quantity = int(quantity)
else:
quantity = round(float(quantity), int(indexOfOneLot))
print(f"""
##### SELL #####
Pair : {str(car.pair)}
Cash : {str(car.price)}
Quantity : {str(car.quantity)}
Price : {str(car.price)}
""")
We can use the Log10 function to get rounding precision from the Binance /api/v3/exchangeinfo endpoint data.
CurrencyRoundNum = int(math.Abs(math.Log10(stepSize)))
PriceRoundNum = int(math.Abs(math.Log10(tickSize)))
The full version on golang is here, or at go playground. I'm sorry that code is not on python.
So I was struggling with the LOT_SIZE error myself.
Previously I was using the round_step_size function from the python-binance library, however, I had to edit this function to deal with this API error.
Here is a function that I use:
from decimal import Decimal, ROUND_DOWN
import math
from typing import Union
def round_step_size(quantity: Union[float, Decimal], step_size: Union[float, Decimal]) -> float:
if step_size == 1.0:
return math.floor(quantity)
elif step_size < 1.0:
return Decimal(f'{quantity}').quantize(Decimal(f'{step_size}'), rounding=ROUND_DOWN)