I am trying to price a Digital Call option using Quantlib Python package, but I have an inconsistent result. I am trying to price a deep ITM option with a 1 day maturity. The thing is that it returns me 0, which doesn't make sense. Could you please help me?
def Digital_Call(s0: float,
strike: float,
risk_free: float,
vol: float,
today: datetime,
maturity: datetime,
cash_payoff: float):
"Output: option_npv"
dividend_yield = 0
riskFreeTS = ql.YieldTermStructureHandle(ql.FlatForward(today, risk_free, ql.ActualActual()))
dividendTS = ql.YieldTermStructureHandle(ql.FlatForward(today, dividend_yield, ql.ActualActual()))
volatility = ql.BlackVolTermStructureHandle(ql.BlackConstantVol(today, ql.NullCalendar(), vol, ql.ActualActual()))
initialValue = ql.QuoteHandle(ql.SimpleQuote(s0))
process = ql.BlackScholesMertonProcess(initialValue, dividendTS, riskFreeTS, volatility)
engine = ql.AnalyticEuropeanEngine(process)
option_type = ql.Option.Call
option = ql.VanillaOption(ql.CashOrNothingPayoff(option_type, strike, cash_payoff), ql.EuropeanExercise(maturity))
option.setPricingEngine(engine)
return option
s0=150
strike = 14.36
risk_free = 0.0302373913
#risk_free = 0
vol = 0.2567723271
today = datetime(2022,9,28)
maturity = datetime(2022,9,30) #it doesn't work with Maturity of both 1 & 2 days
cash_payoff = 30
It returns 0.
Thank You
i try to put some orders at a specific price.
For example i would like to put 20 dollars to buy some ETHUSDT at 800 usdt but it gives me this error:
binance.exceptions.BinanceAPIException: APIError(code=-1106): Parameter 'quoteOrderQty' sent when not required.
there is my call function:
buy_order = client.create_order(
symbol = "ETHUSDT",
price = 800,
quoteOrderQty = 25,
side = client.SIDE_BUY,
type = client.ORDER_TYPE_LIMIT,
timeInForce = client.TIME_IN_FORCE_GTC)
but i dont have any error when i put this :
buy_order = client.create_test_order(symbol="ETHUSDT", side='BUY', type='MARKET', quoteOrderQty=10)
to be honnest actually i do that:
def putOrderBuy_at_price(self, symbol, amount, price):
monney_price = self.client.get_symbol_ticker(symbol=symbol)
# Calculate how much ETH $200 can buy
print(monney_price['price'])
i = 10
while i != 0:
try:
buy_quantity = round(amount / float(price), i)
print("-----------", buy_quantity)
#ETHUSDT
buy_order = self.client.create_order(
symbol = symbol,
price = price,
quantity = buy_quantity,
side = self.client.SIDE_BUY,
type = self.client.ORDER_TYPE_LIMIT,
timeInForce = self.client.TIME_IN_FORCE_GTC)
break
except Exception:
print(i)
i -= 1
And i think there is a better way for that.
Thanks for yours answers
quoteOrderQty is only for MARKET order.
Here is my code:
chosen_year = int(input("Enter the year of interest: "))
print("")
min_life_exp = 999.9
max_life_exp = -1.1
min_life_entity = ""
max_life_entity = ""
min_year = 9999
max_year = -1
chosen_min_life_exp = 999.9
chosen_max_life_exp = -1.1
chosen_min_life_entity = ""
chosen_max_life_entity = ""
with open("life-expectancy.csv") as life_file:
for line in life_file:
parts = line.split(",")
entity = parts[0]
code = parts[1]
year = int(parts[2])
life_exp = float(parts[3])
if max_life_exp < life_exp:
max_life_exp = life_exp
max_life_entity = entity
max_year = year
if min_life_exp > life_exp:
min_life_exp = life_exp
min_life_entity = entity
min_year = year
if chosen_year == year:
avg_life_exp = sum(life_exp) / len(life_exp)
if chosen_max_life_exp < life_exp:
chosen_max_life_exp = life_exp
chosen_max_life_entity = entity
if chosen_min_life_exp > life_exp:
chosen_min_life_exp = life_exp
chosen_min_life_entity = entity
print(f"The overall max life expectancy is: {max_life_exp} from {max_life_entity} in {max_year}")
print(f"The overall max life expectancy is: {min_life_exp} from {min_life_entity} in {min_year}")
print("")
print(f"For the year {chosen_year}:")
print(f"The average life expectancy across all countries was {avg_life_exp:.2f}")
print(f"The max life expectancy was in {chosen_max_life_entity} with {chosen_max_life_exp}")
print(f"The max life expectancy was in {chosen_min_life_entity} with {chosen_min_life_exp}")
I get this error when I run it:
line 38, in <module>
avg_life_exp = sum(life_exp) / len(life_exp)
TypeError: 'float' object is not iterable
how do I change my avg_life_exp to get an average of the life expectancies in the year the user asks for?
To fix this current error, you just need to remove the sum() function Since life_exp is a currently a float. However, I’m guessing you want all of the life_exp in a list, then get the sum of them. To fo this, have the “sum” chunk of the code after reading the lines from the file, since you want to add everything up /after/ you get all the life_exp in each line in the list. If you’d like more specifics, please clarify your question and the expected output.
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)
I am trying to get test data from two CSV files. However whenever I put a test case in for example:
val = Test_data("AAPL.csv", "close", 25)
print (val)
I get:
Open.append(temp[1])
IndexError: list index out of range
I have tried changing the file to read, readlines, and readline.
def main():
pass
if __name__ == '__main__':
main()
def test_data(filename, col, day):
"""A test function to query the data you loaded into your program.
Args:
filename: A string for the filename containing the stock data,
in CSV format.
col: A string of either "date", "open", "high", "low", "close",
"volume", or "adj_close" for the column of stock market data to
look into.
The string arguments MUST be LOWERCASE!
day: An integer reflecting the absolute number of the day in the
data to look up, e.g. day 1, 15, or 1200 is row 1, 15, or 1200
in the file.
Returns:
A value selected for the stock on some particular day, in some
column col. The returned value *must* be of the appropriate type,
such as float, int or str.
"""
Date = list()
Open = list()
High = list()
Low = list()
Close = list()
AdjClose = list()
Volume = list()
file = open(filename, "r")
x= file.read()
for line in x:
temp = line.split(",")
Date.append(temp[0])
Open.append(temp[1])
High.append(temp[2])
Low.append(temp[3])
Close.append(temp[4])
AdjClose.append(temp[5])
Volume.append(temp[6])
if col == 'Date':
return Date[day - 1]
elif col == 'Open':
return Open[day - 1]
elif col == 'High':
return High[day - 1]
elif col == 'Low':
return Low[day - 1]
elif col == 'Close':
return Close[day - 1]
elif col == 'Adj close':
return AdjClose[day - 1]
elif col == 'Volume':
return Volume[day - 1]
def transact(funds, stocks, qty, price, buy=False, sell=False):
"""A bookkeeping function to help make stock transactions.
Args:
funds: An account balance, a float; it is a value of how much money you have,
currently.
stocks: An int, representing the number of stock you currently own.
qty: An int, representing how many stock you wish to buy or sell.
price: An float reflecting a price of a single stock.
buy: This option parameter, if set to true, will initiate a buy.
sell: This option parameter, if set to true, will initiate a sell.
Returns:
Two values *must* be returned. The first (a float) is the new
account balance (funds) as the transaction is completed. The second
is the number of stock now owned (an int) after the transaction is
complete.
Error condition #1: If the `buy` and `sell` keyword parameters are both set to true,
or both false. You *must* print an error message, and then return
the `funds` and `stocks` parameters unaltered. This is an ambiguous
transaction request!
Error condition #2: If you buy, or sell without enough funds or
stocks to sell, respectively. You *must* print an error message,
and then return the `funds` and `stocks` parameters unaltered. This
is an ambiguous transaction request!
"""
if buy == sell:
# print("Ambigious transaction! Can't determine whether to buy or sell. No action performed.")
return funds, stocks
elif buy and funds >= qty * price:
funds -= qty * price
stocks += qty
# print("Insufficient funds")
return funds, stocks
elif sell and stocks >= qty:
funds += qty * price
stocks -= qty
# print("Insufficient stock")
return funds, stocks
Error:
import project
cash_balance = 1000
stocks_owned = 25
price = test_data("AAPL.csv", "close", 42)
Traceback (most recent call last):
File "<input>", line 1, in <module>
NameError: name 'test_data' is not defined
What Im supposed to get:
>>> cash_balance = 1000
>>> stocks_owned = 25
>>> price = test_data("AAPL.csv", "close", 42)
>>> price
4.357143
I don't know if the problem is because it is not reading my data.
Aren't you supposed to do project.test_data()?
Or from project import test_data?