I got a little problem with ccxt on Python. I'm (trying) to code a trading bot which takes my custom tradingview signal. So I've been tinkering a little test code which opens a trade on testnet.binance with all my balance avalaible on BTC/USDT and with a certain leverage.
However, I have a problem with the leverage. Indeed, the code mentions a leverage of 10 and when I run the code locally, the UI mentions a leverage 'Isolated x10' but does not take it into account in the position size (see pictures). I have an approximate balance of 2600 USDT and a trade value of 2600 USDT.
Position through the code
Doing it manually via the UI and with 100% of my balance as well I do get a value of 26000 USDT in 'Isolated x10' which is expected.
Position through the UI
Do you have any idea why it takes into account the leverage but does not apply it to the position?
Here is the code:
import ccxt
import config
binaance = ccxt.binance({
'enableRateLimit': True,
'options': {
'defaultType': 'future',
},
'apiKey': config.API_KEY,
'secret': config.API_SECRET,
'passphrase': config.PASSPHRASE,
})
binaance.set_sandbox_mode(True)
markets = binaance.load_markets()
symbol = 'BTC/USDT'
market = binaance.market(symbol)
binaance.fapiPrivate_post_leverage({
'symbol': 'BTCUSDT',
'leverage': 10,
})
def trade_crypto(request):
free_balance = float(binaance.fetch_balance().get('USDT').get('free'))
last_price = float(binaance.fetchTicker('BTC/USDT').get('last'))
amount = free_balance / last_price
order = binaance.create_market_buy_order('BTC/USDT', amount)
return order
Thank you for what you are doing here ! It helps a lot.
[Edit 1 after #Sam answer]
Hey #Sam, first of all, thank you a lot for your answer.
I didn't checked the margin on the right so thanks for that ! I was so sure that my amout calculations was right that I was not looking there. If I understood correctly the order has engaged 10% of my capital (260 USDT) to obtain 10x leverage with a trade value of 2600 USDT. So I made a change in the calculation which is:
leverage = 10
amount = (free_balance / last_price) * leverage
Result = (2600 / 38900) * 10 = approximately 0.6 btc
But then I got ''Insufficient Funds'' which is expected because it is trying to order with 26 000 USDT from my available balance, but the account only have 2 600.
So how to take in account the fact that the trade value must be 10x the value of my balance (=26 000 USDT) while engaging only 2600 USDT (which is possible trough the user interface)?
In this picture Buying trough the UI, we can see that with 10x leverage I can put my 2600 USDT available balance with a trade value of approximately 26 000 USD. I can't reproduce this behavior code wise.. Hope you or someone else can enlighten me aha.
Ps : I may not have mentioned it, but it concerns trading on futures perpetual contracts
[Edit 2 after finding answer]
I finaly found the mistake. I had to multiply my 'amount' settings by the leverage to get the price in BTC with leverage and put only 99% of this amount because apparently, it can't put 100% of my balance (or maybe it can but I didn't found how to do it. Because with my method, the last price can vary and therefore change the amount which can't be bought or sold with my total balance).
I still have to find a way to put 100% of my balance (perhaps with a parameter that would not take into account the last price).
code modifications:
amount = ((free_balance / last_price) * 10 ) * 0.99
It is taking it into account, you can see that your margin is about 260 USDT and your size is 2600, you would need to place an order for 26000 USDT to use 10x leverage.
You're making an order for about 0.06 BTC, it's going to buy 0.06 BTC for you. At 10x leverage, that's going to cost you about 260 USDT, if you want to use your full 2600 USDT, you need to make an order for 0.6 BTC if you want to use the full amount of USDT that you have.
Related
As far as I am aware the only way to create a new futures order is with client.futures_create_order(). The issue is this requires you to give it the exact amount of contracts you would like to buy. I am using BUSD to make all my trades, so I am wondering if there is any way to give it a BUSD amount or a percentage of the BUSD I have, instead of the amount of order contracts? If the answer is no then is there any way to calculate how many contracts to buy with a specified amount of BUSD or a percentage of the BUSD you have in your wallet.
I am currently using client.futures_create_order() to execute trades. I am using Binance hedge mode so to place a Long I use, side = 'BUY',positionSide: 'LONG'. Then to sell I keep the positionSide as 'LONG' but switch the side to 'SELL' and opposite for shorts. One of the requirements of using the create order is listing the amount of order contracts you want to buy or sell. But I would like to use 5% of my BUSD account balance per trade. I found a way to pull the price of the symbol I want to trade and then calculate how much 5% of my account balance is into BUSD then finally multiply it by the symbol price to get the number of order contracts to buy. But even that comes with its own issues, one being rounding. If I am buying DOGE Binance wont let me buy less than one contract so would need it to round to the nearest whole number. But if I am buying BTC obviously rounding to a whole number isn't helpful. Even if we can some how get around this issue there is one more. I am making more than one trade at a time, so lets say I place a Long with 5% of my BUSD balance which at the time lets say is $5. Within the time of buying and selling my account balance will change. So when it goes to place the sell order it again uses 5% but now that only $4.5 so there is still $0.5 in the trade open. If using a percentage isn't possible, being able to use a fixed amount of BUSD would still be a huge benefit over using a contract amount.
for people that are having this issue I figured out a solution, it's not perfect but it works for me.
FIL3MIN_original_quantity=None
#app.route('/test', methods = ['POST'])
def test():
data = json.loads(request.data)
side = data['order_action']
positionSide = data['positionSide']
command = data['command']
global FIL3MIN_original_quantity
if command == "FIL3MINBUY":
key = "https://api.binance.com/api/v3/ticker/price?symbol=FILBUSD"
hey = requests.get(key)
hey = hey.json()
sym_price =(f"{hey['price']}")
ticker_price = float(sym_price)
acc_balance = client.futures_account_balance()[8]
balance_value = acc_balance['balance']
balance_value = float(balance_value)
BUSD_quantity = balance_value * 0.02
quantitys = BUSD_quantity/ticker_price
quantityss =quantitys*20
quantityss = round(quantityss, 1)
executed_order = client.futures_create_order(symbol='FILBUSD',side=side,positionSide=positionSide,
type=ORDER_TYPE_MARKET, quantity=quantityss)
FIL3MIN_original_quantity = executed_order['origQty']
if executed_order: return {"code": "success", "message": "order executed BUY",
"amount bought": FIL3MIN_original_quantity}
else: return{"code": "error","message": "order failed"}
if command == "FIL3MINSELL":
if FIL3MIN_original_quantity == None:return("No open position to close")
else:executed_order2 = client.futures_create_order(symbol='FILBUSD',side=side,positionSide = positionSide ,
type=ORDER_TYPE_MARKET, quantity=FIL3MIN_original_quantity)
FIL3MIN_original_quantity=None
if executed_order2: return {"code": "success","message": "order executed SELL"}
else:return {"code": "error","message": "order failed"}
I know this looks like a complete mess but it works for me. to simplify what is going on the progragam first looks at the message it is give in which looks something like this.
place the buy order.
{"passphrase": "abc123","order_action": "BUY","positionSide": "LONG", "command": "FIL3MINBUY"}
place the sell order.
{"passphrase": "abc123","order_action": "SELL","positionSide": "LONG", "command": "FIL3MINSELL"}
from that line of code it receives form trading view it then calculated the current price of the symbol which in this case is FILBUSD. Then gets my current BUSD account balance to figure out what 2% is. It then converts 2% of BUSD into the amount of contracts then rounds it. Next it places the buy order and remembers the amount of contracts that were bought and stores it in FIL3MIN_original_quantity. Then once it receives the sell order from trading view it pulls the amount of contracts and places the sell order.
I have a trading bot which operates in 'ADAUSDT' with dynamic quantities for buying and selling, being my whole USDT balance the initial quantity, and trading with that same balance + profits or losses (it basically trades and keeps trading with the whole USDT balance over and over again). Here's some code:
from binance.client import Client
import Keys #personal api keys
client = Client(Keys.b_keys, Keys.b_secret)
infoa = client.get_account()
bal= infoa['balances']
i_o = float(bal[11]["free"])
v_min = v_min #some value of ADA, for example: 1.2
order = client.create_order(
symbol = "ADAUSDT" ,
side=SIDE_BUY ,
type=ORDER_TYPE_LIMIT ,
timeInForce = TIME_IN_FORCE_GTC ,
quantity = float(round((i_o) , 8)) ,
price = v_min ,
)
I know that the precision required both for the quoteAsset and for the baseAsset is 8, hence the usage of the round() function in the quantity value for the order itself, but even after that, the API still throws me the error "Precision is over the maximum defined for this asset". Please help me :c
Edit: i_o is my "USDT" balance, which in theory should change with each trade, hence the usage of this variable instead of a plain number for the quantity of each order.
Note: I'm pretty noob at Python lol I just learned some basics a week ago, so it would be amazing if you could elaborate :D
Based on your code and a bit of familiarity with trading crypto I am assuming that the 'balance' you are calculating is your USDT balance and not your ADA balance via i_o = float(bal[11]["free"]) which would mean that you are placing a buy order for an amount of ADA equal to your current USDT balance (rounded) -- are you sure that's what you want to be doing?
To more directly answer your question as to why you are getting that error, I can only deduce that you must be calculating the price at which you would like to buy using a function that includes division and that your resultant v_min is ending up being something like 1.32578935987532098325 and not 1.2.
Therefore, you would like to also round it, for your convenience:
price = float(round(v_min,8)) ,
Code for getting precision data using python Binance API:
from binance.client import Client
client = Client()
info = client.futures_exchange_info()
requestedFutures = ['BTCUSDT', 'ETHUSDT', 'BNBUSDT', 'SOLUSDT', 'DYDXUSDT']
print(
{si['symbol']:si['quantityPrecision'] for si in info['symbols'] if si['symbol'] in requestedFutures}
)
Solution:
I rounded the variable that specifies the price for each buy and sell order, aswell as i_o ("USDT" balance), by 2.
tradingPairs = ['BTCUSDT','ETHUSDT','BNBUSDT']
#Loop though cryptos
for i in range(0,len(tradingPairs)):
info = client.futures_exchange_info()
if info['symbols'][0]['pair'] == tradingPairs[i]:
print("Price Pre ",info['symbols'][0]['pricePrecision'])
pricePrecision = info['symbols'][0]['pricePrecision']
quantityS = 5.2
quantityB = "{:0.0{}f}".format(quantityS, pricePrecision)
The easiest way to do it is like this:
1.
sell_amount = int(0.99 * (float(coins_amount)))
2.
quantity = sell_amount
By the above method, you will be able to sell 99% of your base asset.
I'm trying to create a new futures order with a little money in order to test my bot but gives me errors:
order=client.futures_create_order(symbol=sym,side=f'{signal}',type='MARKET',positionSide= "LONG",quantity=str(coinQuantity),leverage=10)
error=binance.exceptions.BinanceAPIException: APIError(code=-4164): Order's notional must be no smaller than 5.0 (unless you choose reduce only)
I really don't know what notional means in here and what is restricting me,I did this change:
order=client.futures_create_order(symbol=sym,side=f'{signal}',type='MARKET',positionSide= "LONG",quantity=str(coinQuantity),leverage=10,reduceOnly='true')
but also this time it gives me this error:binance.exceptions.BinanceAPIException: APIError(code=-1106): Parameter 'reduceOnly' sent when not required.
coinQuantity is 0.001 and symbol is 'ETHUSDT'.
python 3.7.9
The new update from binance will not let trades in futures to be made using api less than 5 dollars(and that was what notional was meant!) so I needed to make my trade a bit bigger than 5 dollars like 5.01. and positionSide(and reduceOnly) parameter was absolutely unnecessary ,since it is only needed for hedge mood.
The new update.
The quantity parameter is not calculated in USDT, you need to set quantity of asset you are trading with. For example, let's say that 1 BAT = 0.423 USDT at the moment, and you want to trade with 5 USDT, so:
5 / 0,423 = 11.82
That means that your quantity parameter should be at least 11.82.
I want to place a market long order with take profit and stop loss and a short position the same way. I need to use leverage and isolated mode. I have configured the leverage, isolated mode, how much margin I want to use, and the quantity. I have a problem understanding the Binance docs. Can somebody provide me the code I need to use to place a market long order with take profit and stop loss and a short position?
As I understand, you can't do it in one order via Binance API
You need to place 3 orders in order to implement this:
Initial order to open your SHORT or LONG position (type: "BUY" for long; type: "SELL" for short)
TAKE-PROFIT order
STOP order
This is the way that Binance handles your margin order with both stop-loss and take profit
It can be done like this for SHORT position in python (if you need to open LONG instead of SHORT just change "BUY" to "SELL" and "SELL" to "BUY":
from binance import Client
client = Client(api_key, api_secret)
quantity = 0.001
symbol = "BTCUSDT"
tp_price = 22800
sl_price = 22000
client.futures_create_order(symbol=symbol, side="SELL", type="MARKET", quantity=quantity)
client.futures_create_order(symbol=symbol, side="BUY", type="TAKE_PROFIT_MARKET", quantity=quantity, stopPrice=tp_price)
client.futures_create_order(symbol=symbol, side="BUY", type="STOP_MARKET", quantity=quantity, stopPrice=sl_price)
I'm playing with Binance API to make my trading bot with Python 3.6. and CCXT library (here you find the docs ).
One very useful thing they have in their site is the capability to place orders for a percentage of your current balance:
for example if I'm lookin at BTC/USDT crypto coin pair, and I have 50 USDT on my account, I can choose between buying N amount of BTC or using 100% of my account's USDT for buying, consequently buying the maximum amount of BTC I can.
I read the docs many times, but I can't find the option to do these "percentage of balance" orders with the API in any way: the only thing I can do is passing a float to the order function.
This is how i place orders now:
amount = 0.001
symbol = "BTC/USDT"
def buyorder(amount, symbol): # this makes a market order taking in the amount I defined before, for the pair defined by "symbol"
type = 'market' # or 'limit'
side = 'buy' # or 'sell'
params = {} # extra params and overrides if needed
order = exchange.create_order(symbol, type, side, amount, params)
Do anyone know if there is a built-in capability to do
a percentage order? If API gives no way to do so, would you suggest some workarounds?
I want to be able to give to the API percentage of my current balance as an amount, so I can always use the full of it without having to update when fees are detracted
Use a custom function like this:
def get_max_position_available():
to_use = float(exchange.fetch_balance().get('USDT').get('free'))
price = float(exchange.fetchTicker('BTC/USDT').get('last'))
decide_position_to_use = to_use / price
return decide_position_to_use
I don't know of any Binance API function that does that, but you can try something like this:
# You ask for the balance
balance= client.get_asset_balance(asset='USDT')
# set the percentage or fraction you want to invest in each order
portion_balance = float(balance['free']) * 0.35
# you assign the created variable in the quantity of your order
sell_market = client.order_market_sell(
symbol= 'ETHUSDT',
quantity= portion_balance)
Greetings ;)