89 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			89 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| import logging
 | |
| from typing import Dict, List, Tuple
 | |
| 
 | |
| import ccxt
 | |
| 
 | |
| from freqtrade.enums import MarginMode, TradingMode
 | |
| from freqtrade.exceptions import DDosProtection, OperationalException, TemporaryError
 | |
| from freqtrade.exchange import Exchange
 | |
| from freqtrade.exchange.common import retrier
 | |
| 
 | |
| 
 | |
| logger = logging.getLogger(__name__)
 | |
| 
 | |
| 
 | |
| class Okx(Exchange):
 | |
|     """Okx exchange class.
 | |
| 
 | |
|     Contains adjustments needed for Freqtrade to work with this exchange.
 | |
|     """
 | |
| 
 | |
|     _ft_has: Dict = {
 | |
|         "ohlcv_candle_limit": 300,
 | |
|         "mark_ohlcv_timeframe": "4h",
 | |
|         "funding_fee_timeframe": "8h",
 | |
|     }
 | |
|     _ft_has_futures: Dict = {
 | |
|         "tickers_have_quoteVolume": False,
 | |
|     }
 | |
| 
 | |
|     _supported_trading_mode_margin_pairs: List[Tuple[TradingMode, MarginMode]] = [
 | |
|         # TradingMode.SPOT always supported and not required in this list
 | |
|         # (TradingMode.MARGIN, MarginMode.CROSS),
 | |
|         # (TradingMode.FUTURES, MarginMode.CROSS),
 | |
|         (TradingMode.FUTURES, MarginMode.ISOLATED),
 | |
|     ]
 | |
| 
 | |
|     def _get_params(
 | |
|         self,
 | |
|         ordertype: str,
 | |
|         leverage: float,
 | |
|         reduceOnly: bool,
 | |
|         time_in_force: str = 'gtc',
 | |
|     ) -> Dict:
 | |
|         params = super()._get_params(
 | |
|             ordertype=ordertype,
 | |
|             leverage=leverage,
 | |
|             reduceOnly=reduceOnly,
 | |
|             time_in_force=time_in_force,
 | |
|         )
 | |
|         if self.trading_mode == TradingMode.FUTURES and self.margin_mode:
 | |
|             params['tdMode'] = self.margin_mode.value
 | |
|         return params
 | |
| 
 | |
|     @retrier
 | |
|     def _lev_prep(self, pair: str, leverage: float, side: str):
 | |
|         if self.trading_mode != TradingMode.SPOT and self.margin_mode is not None:
 | |
|             try:
 | |
|                 # TODO-lev: Test me properly (check mgnMode passed)
 | |
|                 self._api.set_leverage(
 | |
|                     leverage=leverage,
 | |
|                     symbol=pair,
 | |
|                     params={
 | |
|                         "mgnMode": self.margin_mode.value,
 | |
|                         # "posSide": "net"",
 | |
|                     })
 | |
|             except ccxt.DDoSProtection as e:
 | |
|                 raise DDosProtection(e) from e
 | |
|             except (ccxt.NetworkError, ccxt.ExchangeError) as e:
 | |
|                 raise TemporaryError(
 | |
|                     f'Could not set leverage due to {e.__class__.__name__}. Message: {e}') from e
 | |
|             except ccxt.BaseError as e:
 | |
|                 raise OperationalException(e) from e
 | |
| 
 | |
|     def get_max_pair_stake_amount(
 | |
|         self,
 | |
|         pair: str,
 | |
|         price: float,
 | |
|         leverage: float = 1.0
 | |
|     ) -> float:
 | |
| 
 | |
|         if self.trading_mode == TradingMode.SPOT:
 | |
|             return float('inf')  # Not actually inf, but this probably won't matter for SPOT
 | |
| 
 | |
|         if pair not in self._leverage_tiers:
 | |
|             return float('inf')
 | |
| 
 | |
|         pair_tiers = self._leverage_tiers[pair]
 | |
|         return pair_tiers[-1]['max'] / leverage
 |