Skip to content

Commit

Permalink
[BinanceExchange] Add future support
Browse files Browse the repository at this point in the history
  • Loading branch information
Herklos committed Jun 16, 2021
1 parent 02ad882 commit 4ad3ff9
Show file tree
Hide file tree
Showing 2 changed files with 135 additions and 3 deletions.
136 changes: 134 additions & 2 deletions Trading/Exchange/binance/binance_exchange.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,32 @@
import octobot_trading.exchanges as exchanges


class Binance(exchanges.SpotCCXTExchange):
class Binance(exchanges.SpotCCXTExchange, exchanges.FutureCCXTExchange):
DESCRIPTION = ""

BUY_STR = "BUY"
SELL_STR = "SELL"

ACCOUNTS = {
trading_enums.AccountTypes.CASH: 'cash'
trading_enums.AccountTypes.CASH: 'cash',
trading_enums.AccountTypes.FUTURE: 'future'
}

FUNDING_WITH_MARK_PRICE = True

BINANCE_FUTURE_QUANTITY = "positionAmt"
BINANCE_FUTURE_UNREALIZED_PNL = "unRealizedProfit"
BINANCE_FUTURE_LIQUIDATION_PRICE = "liquidationPrice"
BINANCE_FUTURE_VALUE = "liquidationPrice"

BINANCE_MARGIN_TYPE_ISOLATED = "ISOLATED"
BINANCE_MARGIN_TYPE_CROSSED = "CROSSED"

BINANCE_FUNDING_RATE = "lastFundingRate"
BINANCE_NEXT_FUNDING_TIME = "nextFundingTime"
BINANCE_TIME = "time"
BINANCE_MARK_PRICE = "markPrice"
BINANCE_ENTRY_PRICE = "entryPrice"

@classmethod
def get_name(cls):
Expand Down Expand Up @@ -98,3 +113,120 @@ def _fill_order_missing_data(self, order, trades):
if not order[trading_enums.ExchangeConstantsOrderColumns.FEE.value] and order_id in trades:
order[trading_enums.ExchangeConstantsOrderColumns.FEE.value] = \
trades[order_id][trading_enums.ExchangeConstantsOrderColumns.FEE.value]

async def get_open_positions(self) -> dict:
return [
self.parse_position(position)
for position in await self.connector.client.fapiPrivate_get_positionrisk()
]

async def get_mark_price(self, symbol: str) -> dict:
return (await self.get_mark_price_and_funding(symbol))[0]

async def get_funding_rate(self, symbol: str):
return (await self.get_mark_price_and_funding(symbol))[1]

async def get_mark_price_and_funding(self, symbol: str) -> tuple:
return self._parse_mark_price_and_funding_dict(await self.connector.client.fapiPublic_get_premiumindex(
{"symbol": self.get_exchange_pair(symbol)}))

async def get_funding_rate_history(self, symbol: str, limit: int = 1) -> list:
return [
self.parse_funding(funding_rate_dict)
for funding_rate_dict in (await self.connector.client.fapiPublic_get_funding_rate(
{"symbol": self.get_exchange_pair(symbol),
"limit": limit}))
]

async def set_symbol_leverage(self, symbol: str, leverage: int):
await self.connector.client.fapiPrivate_post_leverage(
{"symbol": self.get_exchange_pair(symbol),
"leverage": leverage})

async def set_symbol_margin_type(self, symbol: str, isolated: bool):
await self.connector.client.fapiPrivate_post_marginType(
{"symbol": self.get_exchange_pair(symbol),
"marginType": self.BINANCE_MARGIN_TYPE_ISOLATED if isolated else self.BINANCE_MARGIN_TYPE_CROSSED})

def parse_position(self, position_dict):
try:
position_dict.update({
trading_enums.ExchangeConstantsPositionColumns.SYMBOL.value:
self.get_pair_from_exchange(
position_dict[trading_enums.ExchangeConstantsPositionColumns.SYMBOL.value]),
trading_enums.ExchangeConstantsPositionColumns.ID.value:
self.connector.client.safe_string(position_dict,
trading_enums.ExchangeConstantsPositionColumns.ID.value,
position_dict[
trading_enums.ExchangeConstantsPositionColumns.SYMBOL.value]),
trading_enums.ExchangeConstantsPositionColumns.QUANTITY.value:
self.connector.client.safe_float(position_dict, self.BINANCE_FUTURE_QUANTITY, 0),
trading_enums.ExchangeConstantsPositionColumns.VALUE.value:
self.calculate_position_value(
self.connector.client.safe_float(
position_dict, trading_enums.ExchangeConstantsPositionColumns.QUANTITY.value, 0),
self.connector.client.safe_float(
position_dict, trading_enums.ExchangeConstantsPositionColumns.MARK_PRICE.value, 1)),
trading_enums.ExchangeConstantsPositionColumns.MARGIN.value:
# TODO
self.connector.client.safe_float(position_dict,
trading_enums.ExchangeConstantsPositionColumns.MARGIN.value,
0),
trading_enums.ExchangeConstantsPositionColumns.UNREALISED_PNL.value:
self.connector.client.safe_float(position_dict, self.BINANCE_FUTURE_UNREALIZED_PNL, 0),
trading_enums.ExchangeConstantsPositionColumns.REALISED_PNL.value:
# TODO
self.connector.client.safe_float(position_dict,
trading_enums.ExchangeConstantsPositionColumns.REALISED_PNL.value,
0),
trading_enums.ExchangeConstantsPositionColumns.LIQUIDATION_PRICE.value:
self.connector.client.safe_float(position_dict, self.BINANCE_FUTURE_LIQUIDATION_PRICE, 0),
trading_enums.ExchangeConstantsPositionColumns.MARK_PRICE.value:
self.connector.client.safe_float(position_dict, self.BINANCE_MARK_PRICE, 0),
trading_enums.ExchangeConstantsPositionColumns.ENTRY_PRICE.value:
self.connector.client.safe_float(position_dict, self.BINANCE_ENTRY_PRICE, 0),
trading_enums.ExchangeConstantsPositionColumns.TIMESTAMP.value:
# TODO
self.connector.client.safe_float(position_dict,
trading_enums.ExchangeConstantsPositionColumns.TIMESTAMP.value,
self.connector.get_exchange_current_time()),
trading_enums.ExchangeConstantsPositionColumns.STATUS.value:
self.parse_position_status(self.connector.client.safe_string(position_dict,
trading_enums.ExchangeConstantsPositionColumns.STATUS.value,
default_value=trading_enums.PositionStatus.OPEN.value)),
trading_enums.ExchangeConstantsPositionColumns.SIDE.value:
self.parse_position_side(self.connector.client.safe_string(position_dict,
trading_enums.ExchangeConstantsPositionColumns.SIDE.value,
default_value=trading_enums.PositionSide.UNKNOWN.value)),
})
except KeyError as e:
self.logger.error(f"Fail to parse position dict ({e})")
return position_dict

def parse_funding(self, funding_dict, from_ticker=False):
try:
funding_dict = {
trading_enums.ExchangeConstantsFundingColumns.LAST_FUNDING_TIME.value:
self.parse_timestamp(funding_dict, self.BINANCE_TIME),
trading_enums.ExchangeConstantsFundingColumns.FUNDING_RATE.value:
self.connector.client.safe_float(funding_dict, self.BINANCE_FUNDING_RATE),
trading_enums.ExchangeConstantsFundingColumns.NEXT_FUNDING_TIME.value:
self.parse_timestamp(funding_dict, self.BINANCE_NEXT_FUNDING_TIME)
}
except KeyError as e:
self.logger.error(f"Fail to parse funding dict ({e})")
return funding_dict

def parse_mark_price(self, mark_price_dict, from_ticker=False):
try:
mark_price_dict = {
trading_enums.ExchangeConstantsMarkPriceColumns.MARK_PRICE.value:
self.connector.client.safe_float(mark_price_dict, self.BINANCE_MARK_PRICE, 0)
}
except KeyError as e:
self.logger.error(f"Fail to parse mark_price dict ({e})")
return mark_price_dict

def _parse_mark_price_and_funding_dict(self, mark_price_and_funding_dict):
return self.parse_mark_price(mark_price_and_funding_dict), \
self.parse_funding(mark_price_and_funding_dict)
2 changes: 1 addition & 1 deletion Trading/Exchange/binance/resources/binance.md
Original file line number Diff line number Diff line change
@@ -1 +1 @@
Binance is a SpotExchange adaptation for Binance exchange using the REST API.
Binance is a SpotExchange and FutureExchange adaptation for Binance exchange using the REST API.

0 comments on commit 4ad3ff9

Please sign in to comment.