Skip to content

Commit

Permalink
[Bybit] Add position mode parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
Herklos committed Dec 7, 2021
1 parent 9e2e840 commit 8657bbc
Showing 1 changed file with 64 additions and 63 deletions.
127 changes: 64 additions & 63 deletions Trading/Exchange/bybit/bybit_exchange.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,23 +28,26 @@ class Bybit(exchanges.SpotCCXTExchange, exchanges.FutureCCXTExchange):
BUY_STR = "Buy"
SELL_STR = "Sell"

LONG_STR = BUY_STR
SHORT_STR = SELL_STR

MARK_PRICE_IN_TICKER = True
FUNDING_IN_TICKER = True

# Spot keys
BYBIT_KLINE_TIMESTAMP = "open_time"

BYBIT_SYMBOL = "symbol"

# Position
BYBIT_SIZE = "size"
BYBIT_VALUE = "position_value"
BYBIT_MARGIN = "position_margin"
BYBIT_INITIAL_MARGIN = "position_margin"
BYBIT_STATUS = "position_status"
BYBIT_LIQUIDATION_PRICE = "liq_price"
BYBIT_BANKRUPTCY_PRICE = "bust_price"
BYBIT_CLOSING_FEE = "occ_closing_fee"
BYBIT_MODE = "mode"
BYBIT_TIMESTAMP = "created_at"
BYBIT_IS_ISOLATED = "is_isolated"
BYBIT_REALIZED_PNL = "cum_realised_pnl"
BYBIT_ONE_WAY = "MergedSingle"
BYBIT_HEDGE = "BothSide"

# Funding
BYBIT_FUNDING_TIMESTAMP = "funding_rate_timestamp"
Expand All @@ -65,78 +68,61 @@ async def get_symbol_prices(self, symbol, time_frame, limit: int = 200, **kwargs
except Exception as e:
raise octobot_trading.errors.FailedRequest(f"Failed to get_symbol_prices {e}")

async def initialize_impl(self):
await super().initialize_impl()
def get_default_type(self):
return 'linear'

# temporary patch defaultMarketType to linear
self.connector.client.options['defaultType'] = 'linear'

async def get_open_positions(self) -> list:
async def get_positions(self) -> list:
return self.parse_positions(await self.connector.client.fetch_positions())

# async def get_kline_price(self, symbol, time_frame):
# try:
# await self.connector.client.public_get_kline_list(
# {
# "symbol": self.get_exchange_pair(symbol),
# "interval": "",
# "from": "",
# "limit": 1
# })
# except BaseError as e:
# self.logger.error(f"Failed to get_kline_price {e}")
# return None

def parse_positions(self, positions) -> list:
"""
CCXT is returning the position dict as {'data': {position data dict}}
"""
return [self.parse_position(position.get('data')) for position in positions]
return [self.parse_position(position.get('data')) for position in positions] if positions else []

def parse_position(self, position_dict) -> dict:
try:
size = decimal.Decimal(position_dict.get(self.BYBIT_SIZE, 0))
if size == constants.ZERO:
return {} # Don't parse empty position

symbol = self.get_pair_from_exchange(
position_dict[trading_enums.ExchangeConstantsPositionColumns.SYMBOL.value])
position_dict[trading_enums.ExchangeConstantsPositionColumns.SYMBOL.value])
side = self.parse_position_side(position_dict.get(trading_enums.ExchangePositionCCXTColumns.SIDE.value))
return {
trading_enums.ExchangeConstantsPositionColumns.SYMBOL.value: symbol,
trading_enums.ExchangeConstantsPositionColumns.TIMESTAMP.value:
self.parse_timestamp(position_dict, self.BYBIT_TIMESTAMP),
trading_enums.ExchangeConstantsPositionColumns.SIDE.value:
self.parse_position_side(
position_dict.get(trading_enums.ExchangePositionCCXTColumns.SIDE.value,
trading_enums.PositionSide.UNKNOWN.value)),
trading_enums.ExchangeConstantsPositionColumns.SIDE.value: side,
trading_enums.ExchangeConstantsPositionColumns.MARGIN_TYPE.value:
self._parse_position_margin_type(
position_dict.get(self.BYBIT_IS_ISOLATED, True)),
trading_enums.ExchangeConstantsPositionColumns.QUANTITY.value:
decimal.Decimal(self.connector.client.parse_number(
position_dict.get(self.BYBIT_SIZE, 0))),
trading_enums.ExchangeConstantsPositionColumns.COLLATERAL.value:
decimal.Decimal(self.connector.client.parse_number(
position_dict.get(trading_enums.ExchangeConstantsPositionColumns.COLLATERAL.value, 0))),
self._parse_position_margin_type(position_dict.get(self.BYBIT_IS_ISOLATED, True)),
trading_enums.ExchangeConstantsPositionColumns.SIZE.value:
size if side is trading_enums.PositionSide.LONG else -size,
trading_enums.ExchangeConstantsPositionColumns.INITIAL_MARGIN.value:
decimal.Decimal(position_dict.get(self.BYBIT_INITIAL_MARGIN, 0)),
trading_enums.ExchangeConstantsPositionColumns.NOTIONAL.value:
decimal.Decimal(self.connector.client.parse_number(
position_dict.get(self.BYBIT_VALUE, 0))),
decimal.Decimal(position_dict.get(self.BYBIT_VALUE, 0)),
trading_enums.ExchangeConstantsPositionColumns.LEVERAGE.value:
decimal.Decimal(self.connector.client.parse_number(
position_dict.get(trading_enums.ExchangeConstantsPositionColumns.LEVERAGE.value, 0))),
decimal.Decimal(position_dict.get(
trading_enums.ExchangeConstantsPositionColumns.LEVERAGE.value, 0)),
trading_enums.ExchangeConstantsPositionColumns.UNREALISED_PNL.value:
decimal.Decimal(self.connector.client.parse_number(
position_dict.get(trading_enums.ExchangeConstantsPositionColumns.UNREALISED_PNL.value, 0))),
decimal.Decimal(position_dict.get(
trading_enums.ExchangeConstantsPositionColumns.UNREALISED_PNL.value, 0)),
trading_enums.ExchangeConstantsPositionColumns.REALISED_PNL.value:
decimal.Decimal(self.connector.client.parse_number(
position_dict.get(self.BYBIT_REALIZED_PNL, 0))),
decimal.Decimal(position_dict.get(self.BYBIT_REALIZED_PNL, 0)),
trading_enums.ExchangeConstantsPositionColumns.LIQUIDATION_PRICE.value:
decimal.Decimal(self.connector.client.parse_number(
position_dict.get(self.BYBIT_LIQUIDATION_PRICE, 0))),
trading_enums.ExchangeConstantsPositionColumns.MARK_PRICE.value:
decimal.Decimal(self.connector.client.parse_number(
position_dict.get(trading_enums.ExchangeConstantsPositionColumns.MARK_PRICE.value, 0))),
decimal.Decimal(position_dict.get(self.BYBIT_LIQUIDATION_PRICE, 0)),
trading_enums.ExchangeConstantsPositionColumns.CLOSING_FEE.value:
decimal.Decimal(position_dict.get(self.BYBIT_CLOSING_FEE, 0)),
trading_enums.ExchangeConstantsPositionColumns.BANKRUPTCY_PRICE.value:
decimal.Decimal(position_dict.get(self.BYBIT_BANKRUPTCY_PRICE, 0)),
trading_enums.ExchangeConstantsPositionColumns.ENTRY_PRICE.value:
decimal.Decimal(self.connector.client.parse_number(
position_dict.get(trading_enums.ExchangeConstantsPositionColumns.ENTRY_PRICE.value, 0))),
decimal.Decimal(position_dict.get(
trading_enums.ExchangeConstantsPositionColumns.ENTRY_PRICE.value, 0)),
trading_enums.ExchangeConstantsPositionColumns.CONTRACT_TYPE.value:
self._parse_position_contract_type(symbol),
trading_enums.ExchangeConstantsPositionColumns.POSITION_MODE.value:
self._parse_position_mode(position_dict.get(self.BYBIT_MODE)),
}
except KeyError as e:
self.logger.error(f"Fail to parse position dict ({e})")
Expand All @@ -157,8 +143,8 @@ def parse_funding(self, funding_dict, from_ticker=False):
funding_dict.update({
trading_enums.ExchangeConstantsFundingColumns.LAST_FUNDING_TIME.value:
funding_next_timestamp - self.BYBIT_DEFAULT_FUNDING_TIME,
trading_enums.ExchangeConstantsFundingColumns.FUNDING_RATE.value: self.connector.client.safe_float(
funding_dict, trading_enums.ExchangeConstantsFundingColumns.FUNDING_RATE.value),
trading_enums.ExchangeConstantsFundingColumns.FUNDING_RATE.value: decimal.Decimal(
funding_dict.get(trading_enums.ExchangeConstantsFundingColumns.FUNDING_RATE.value, 0)),
trading_enums.ExchangeConstantsFundingColumns.NEXT_FUNDING_TIME.value: funding_next_timestamp
})
except KeyError as e:
Expand All @@ -172,9 +158,8 @@ def parse_mark_price(self, mark_price_dict, from_ticker=False) -> dict:
try:
mark_price_dict = {
trading_enums.ExchangeConstantsMarkPriceColumns.MARK_PRICE.value:
self.connector.client.safe_float(mark_price_dict,
trading_enums.ExchangeConstantsMarkPriceColumns.MARK_PRICE.value,
0)
decimal.Decimal(mark_price_dict.get(
trading_enums.ExchangeConstantsMarkPriceColumns.MARK_PRICE.value, 0))
}
except KeyError as e:
self.logger.error(f"Fail to parse mark price dict ({e})")
Expand All @@ -190,12 +175,28 @@ def parse_position_status(self, status):
return trading_enums.PositionStatus(self.connector.client.safe_string(statuses, status, status))

def _parse_position_margin_type(self, position_is_isolated):
return trading_enums.TraderPositionType.ISOLATED.value \
if position_is_isolated else trading_enums.TraderPositionType.CROSS.value
return trading_enums.TraderPositionType.ISOLATED \
if position_is_isolated else trading_enums.TraderPositionType.CROSS

def _parse_position_contract_type(self, position_pair):
if self.is_linear_pair(position_pair):
if self.is_linear_symbol(position_pair):
return trading_enums.FutureContractType.LINEAR_PERPETUAL
if self.is_inverse_pair(position_pair):
if self.is_inverse_symbol(position_pair):
return trading_enums.FutureContractType.INVERSE_PERPETUAL
return None

def _parse_position_mode(self, raw_mode):
if raw_mode == self.BYBIT_ONE_WAY:
return trading_enums.PositionMode.ONE_WAY
if raw_mode == self.BYBIT_HEDGE:
return trading_enums.PositionMode.HEDGE
return None

def is_linear_symbol(self, symbol):
return self._get_pair_market_type(symbol) == 'linear'

def is_inverse_symbol(self, symbol):
return self._get_pair_market_type(symbol) == 'inverse'

def is_futures_symbol(self, symbol):
return self._get_pair_market_type(symbol) == 'futures'

0 comments on commit 8657bbc

Please sign in to comment.