[英]How to short an asset on binance with python
python 有没有办法打开一个空头 position 并为某个资产关闭它?
我发现这是正常订单,但不是做空 position。 正常购买:
order = client.create_test_order(
symbol='BNBBTC',
side=Client.SIDE_BUY,
type=Client.ORDER_TYPE_MARKET,
quantity=100)
print("order", order)
方法一:使用ccxt
库:
# -*- coding: utf-8 -*-
import os
import sys
from pprint import pprint
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
sys.path.append(root + '/python')
import ccxt # noqa: E402
print('CCXT Version:', ccxt.__version__)
# Must read before your start:
#
# - https://github.com/ccxt/ccxt/wiki/Manual
# - https://github.com/ccxt/ccxt/wiki/Manual#implicit-api-methods
# - https://github.com/ccxt/ccxt/wiki/Manual#unified-api
#
# In short, Binance's API is structured as follows and you should understand
# the meaning and the difference between ISOLATED vs CROSSED margin mode and
# the difference between Hedged positions vs One-way positions.
#
# - wapi: funding for withdrawals and deposits (wapi)
# - api: spot (api)
# - sapi: spot margin
# - CROSSED margin mode
# - Hedged positions
# - One-way positions
# - ISOLATED margin mode
# - Hedged positions
# - One-way positions
# - fapi: swap/perpetual futures margin
# - CROSSED margin mode
# - Hedged positions
# - One-way positions
# - ISOLATED margin mode
# - Hedged positions
# - One-way positions
# - dapi: classic delivery futures margin
# - CROSSED margin mode
# - Hedged positions
# - One-way positions
# - ISOLATED margin mode
# - Hedged positions
# - One-way positions
#
# You should pick the following:
#
# 1. which API you want to trade (fapi, i believe)
# 2. which specific margin mode you want (CROSSED or ISOLATED)
# 3. which specific position mode you want (Hedged or One-way)
#
# Differences in margin modes:
#
# - CROSSED margin mode = you have one futures-margin account for all your positions,
# if some position requires too much margin, your entire account is affected,
# leaving less margin for the other positions,
# thus you share the same margin _"across"_ all your positions
#
# - ISOLATED margin mode = you have separate futures-margin for each of your positions,
# if some position runs out of margin the other positions are not affected,
# thus your positions are _"isolated"_ from one another
#
# Difference in position modes:
#
# - One-way position mode - when you're in this mode
# there's no such things as LONG or SHORT positions.
# You just buy or sell a number of contracts, and
# if the price goes down, your PnL goes negative,
# if the price goes up, your PnL is positive.
# Thus, the position operates `BOTH` ways, both long and short at the same time,
# the notion of "long" and "short" is abstracted away from you,
# so there's only one way the position can go and that way is called "BOTH".
#
# - Hedge mode - you either enter a `LONG` position or a `SHORT` position and
# your PnL calculation rules depend on that
# so there's a number of ways a position can go
#
# Which specific mode of trading (margin mode + position mode) do you want?
def table(values):
first = values[0]
keys = list(first.keys()) if isinstance(first, dict) else range(0, len(first))
widths = [max([len(str(v[k])) for v in values]) for k in keys]
string = ' | '.join(['{:<' + str(w) + '}' for w in widths])
return "\n".join([string.format(*[str(v[k]) for k in keys]) for v in values])
exchange = ccxt.binance({
'apiKey': 'YOUR_API_KEY',
'secret': 'YOUR_SECRET',
'options': {
'defaultType': 'future',
},
})
markets = exchange.load_markets()
symbol = 'BTC/USDT' # YOUR SYMBOL HERE
market = exchange.market(symbol)
exchange.verbose = True # UNCOMMENT THIS AFTER LOADING THE MARKETS FOR DEBUGGING
print('----------------------------------------------------------------------')
print('Fetching your balance:')
response = exchange.fetch_balance()
pprint(response['total']) # make sure you have enough futures margin...
# pprint(response['info']) # more details
print('----------------------------------------------------------------------')
# https://binance-docs.github.io/apidocs/futures/en/#position-information-v2-user_data
print('Getting your positions:')
response = exchange.fapiPrivateV2_get_positionrisk()
print(table(response))
print('----------------------------------------------------------------------')
# https://binance-docs.github.io/apidocs/futures/en/#change-position-mode-trade
print('Getting your current position mode (One-way or Hedge Mode):')
response = exchange.fapiPrivate_get_positionside_dual()
if response['dualSidePosition']:
print('You are in Hedge Mode')
else:
print('You are in One-way Mode')
print('----------------------------------------------------------------------')
# print('Setting your position mode to One-way:')
# response = exchange.fapiPrivate_post_positionside_dual({
# 'dualSidePosition': False,
# })
# print(response)
# print('Setting your positions to Hedge mode:')
# response = exchange.fapiPrivate_post_positionside_dual({
# 'dualSidePosition': True,
# })
# print(response)
# print('----------------------------------------------------------------------')
# # https://binance-docs.github.io/apidocs/futures/en/#change-margin-type-trade
# print('Changing your', symbol, 'position margin mode to CROSSED:')
# response = exchange.fapiPrivate_post_margintype({
# 'symbol': market['id'],
# 'marginType': 'CROSSED',
# })
# print(response)
# print('Changing your', symbol, 'position margin mode to ISOLATED:')
# response = exchange.fapiPrivate_post_margintype({
# 'symbol': market['id'],
# 'marginType': 'ISOLATED',
# })
# print(response)
# print('----------------------------------------------------------------------')
# # https://binance-docs.github.io/apidocs/spot/en/#new-future-account-transfer-futures
# code = 'USDT'
# amount = 123.45
# currency = exchange.currency(code)
# print('Moving', code, 'funds from your spot account to your futures account:')
# response = exchange.sapi_post_futures_transfer({
# 'asset': currency['id'],
# 'amount': exchange.currency_to_precision(code, amount),
# # 1: transfer from spot account to USDT-Ⓜ futures account.
# # 2: transfer from USDT-Ⓜ futures account to spot account.
# # 3: transfer from spot account to COIN-Ⓜ futures account.
# # 4: transfer from COIN-Ⓜ futures account to spot account.
# 'type': 1,
# })
# print('----------------------------------------------------------------------')
# # for ISOLATED positions only
# print('Modifying your ISOLATED', symbol, 'position margin:')
# response = exchange.fapiPrivate_post_positionmargin({
# 'symbol': market['id'],
# 'amount': 123.45, # ←-------------- YOUR AMOUNT HERE
# 'positionSide': 'BOTH', # use BOTH for One-way positions, LONG or SHORT for Hedge Mode
# 'type': 1, # 1 = add position margin, 2 = reduce position margin
# })
# print('----------------------------------------------------------------------')
要查看更多关于币安不同市场的库示例,请参见此处。
方法二:自定义基础 Class
我有一个基础 class 用于此目的,基于主要的 Binance API 文档,您可以使用此 class 或自己定制:
# -*- coding: utf-8 -*-
import requests
import hashlib
import time
from uuid import uuid4
import urllib
import hmac
class BinanceFutures:
base = "https://fapi.binance.com"
def __init__(self, public=None, secret=None):
self.public = public
self.secret = secret
def sign(self, params):
params['timestamp'] = (int(time.time()) * 1000)
params['recvWindow'] = 30000
params_str = urllib.parse.urlencode(params).encode('utf-8')
sign = hmac.new(
key=str.encode(self.secret),
msg=params_str,
digestmod=hashlib.sha256
).hexdigest()
return params_str.decode("utf-8") + "&signature=" + str(sign)
def get_header(self):
return {"X-MBX-APIKEY": self.public, "Content-Type": "application/json"}
def send_request(self, method, endpoint, params):
url = BinanceFutures.base + endpoint + "?" + self.sign(params=params)
response = requests.request(method=method.upper(), url=url, headers=self.get_header()).json()
return response
def get_listenKey(self):
response = self.send_request(method="post", endpoint="/fapi/v1/listenKey", params={})
return response["listenKey"]
def get_ticker(self, symbol):
response = requests.get(BinanceFutures.base + f"/fapi/v1/ticker/price?symbol={symbol}").json()
return float(response["price"])
def set_leverage(self, symbol, leverage, trade_mode=False):
if trade_mode:
response = self.send_request(method="post", endpoint="/fapi/v1/leverage",
params={"symbol": symbol, "leverage": leverage})
return response
else:
return True
def get_funding_fees_sum(self, symbol, start):
params = {
"symbol": symbol,
"incomeType": "FUNDING_FEE",
"startTime": start
}
response = self.send_request(method="get", endpoint="/fapi/v1/income", params=params)
funding_fee = 0
for income in response:
if income['incomeType'] == 'FUNDING_FEE':
if income['time'] >= start:
funding_fee += float(income['income'])
return funding_fee
def get_balance(self):
return self.send_request(method="get", endpoint="/fapi/v2/balance", params={})
def account_info(self):
return self.send_request(method="get", endpoint="/fapi/v2/account", params={})
def send_order(self, order, trade_mode=False):
if trade_mode:
response = self.send_request(method="post", endpoint="/fapi/v1/order", params=order)
else:
response = {
"orderId": str(uuid4()),
"symbol": order["symbol"],
"side": order["side"],
"origQty": float(order["quantity"]),
}
avg_price = self.get_ticker(symbol=order['symbol'])
response["avgPrice"] = avg_price
response["cumQuote"] = avg_price * float(order.get('quantity', 0))
return response
def open_positions(self, symbols=None, trade_mode=True):
if not trade_mode:
return [], 100_000
response = self.send_request(method="get", endpoint="/fapi/v2/account", params={})
positions = response.get("positions", None)
positions = [p for p in positions if float(p['entryPrice']) > 0]
free_usdt = float(response.get("availableBalance", 0))
if symbols:
positions = [p for p in positions if p["symbol"] in symbols]
return positions, free_usdt
def params_filter_futures(self, symbol_, quantity, price=0):
info = requests.get(self.base + '/fapi/v1/exchangeInfo').json()
params = {
'quantity': 0,
'price': 0
}
for symbol in info['symbols']:
if symbol['symbol'] == symbol_:
for f in symbol['filters']:
if f['filterType'] == 'LOT_SIZE':
minQty = float(f['minQty'])
maxQty = float(f['maxQty'])
step = float(f['stepSize'])
quantity = max(quantity, minQty)
quantity = min(quantity, maxQty)
k = round(int(quantity / step))
# quantity = ((k-1) * step) + minQty
quantity = k * step
quantity = round(quantity, symbol['baseAssetPrecision'] - 1)
params['quantity'] = quantity
elif f['filterType'] == 'PRICE_FILTER' and price:
minPrice = float(f['minPrice'])
maxPrice = float(f['maxPrice'])
step = float(f['tickSize'])
price = max(price, minPrice)
price = min(price, maxPrice)
k = round(int(price / step))
price = k * step
price = round(price, symbol['quotePrecision'] - 1)
params['price'] = price
return params
def value2quantity(self, value, symbol):
price = self.get_ticker(symbol=symbol)
quantity = value / price
params = self.params_filter_futures(symbol_=symbol, quantity=quantity, price=0)
return params["quantity"]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.