Skip to content

Commit

Permalink
[PositionUpdater] Adapt to margin exchange
Browse files Browse the repository at this point in the history
  • Loading branch information
Herklos committed Feb 23, 2020
1 parent 6819eb2 commit b8de43f
Show file tree
Hide file tree
Showing 15 changed files with 44 additions and 41 deletions.
1 change: 1 addition & 0 deletions octobot_trading/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
CONFIG_EXCHANGE_KEY = "api-key"
CONFIG_EXCHANGE_SECRET = "api-secret"
CONFIG_EXCHANGE_PASSWORD = "api-password"
CONFIG_EXCHANGE_SANDBOXED = "sandboxed"
CONFIG_EXCHANGE_ENCRYPTED_VALUES = [CONFIG_EXCHANGE_KEY, CONFIG_EXCHANGE_SECRET, CONFIG_EXCHANGE_PASSWORD]

TESTED_EXCHANGES = ["binance", "coinbasepro", "kucoin2"]
Expand Down
2 changes: 1 addition & 1 deletion octobot_trading/data/order.py
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ def parse_order_type(raw_order):
else:
order_type = _get_sell_and_buy_types(order_type)
return side, order_type
except KeyError:
except (KeyError, ValueError):
get_logger(Order.__class__.__name__).error("Failed to parse order type")
return None, None

Expand Down
5 changes: 1 addition & 4 deletions octobot_trading/data/position.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@ cdef class Position(Initializable):
cdef Trader trader
cdef ExchangeManager exchange_manager

cdef public bint is_open

cdef public str symbol
cdef public str currency
cdef public str market
Expand Down Expand Up @@ -58,7 +56,6 @@ cdef class Position(Initializable):
double quantity,
double liquidation_price,
double unrealised_pnl,
int leverage,
bint is_open)
int leverage)

cpdef bint update_position_from_raw(self, dict raw_position)
7 changes: 1 addition & 6 deletions octobot_trading/data/position.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def __init__(self, trader):

def __update(self, position_id, symbol, currency, market,
timestamp, entry_price, mark_price, quantity,
liquidation_price, unrealised_pnl, leverage, is_open):
liquidation_price, unrealised_pnl, leverage):
changed: bool = False

if position_id and self.position_id != position_id:
Expand Down Expand Up @@ -78,10 +78,6 @@ def __update(self, position_id, symbol, currency, market,
if liquidation_price and self.liquidation_price != liquidation_price:
self.liquidation_price = liquidation_price

if is_open and self.is_open != is_open:
self.is_open = is_open
changed = True

return changed

def update_position_from_raw(self, raw_position):
Expand All @@ -98,6 +94,5 @@ def update_position_from_raw(self, raw_position):
"timestamp": raw_position[ExchangeConstantsPositionColumns.TIMESTAMP.value],
"unrealised_pnl": raw_position[ExchangeConstantsPositionColumns.UNREALISED_PNL.value],
"leverage": raw_position[ExchangeConstantsPositionColumns.LEVERAGE.value],
"is_open": raw_position[ExchangeConstantsPositionColumns.IS_OPEN.value],
"mark_price": raw_position[ExchangeConstantsPositionColumns.MARK_PRICE.value]
})
5 changes: 2 additions & 3 deletions octobot_trading/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,10 +179,9 @@ class ExchangeConstantsPositionColumns(Enum):
SYMBOL = "symbol"
LIQUIDATION_PRICE = "liquidationPrice"
MARK_PRICE = "markPrice"
ENTRY_PRICE = "avgEntryPrice"
ENTRY_PRICE = "entryPrice"
UNREALISED_PNL = "unrealisedPnl"
IS_OPEN = "isOpen"
QUANTITY = "currentQty"
QUANTITY = "quantity"
LEVERAGE = "leverage"


Expand Down
1 change: 0 additions & 1 deletion octobot_trading/exchanges/exchange_builder.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ cdef class ExchangeBuilder:
cdef public str exchange_name

cdef bint _is_using_trading_modes
cdef bint _is_exchange_manager_sandboxed

cdef str _matrix_id

Expand Down
9 changes: 3 additions & 6 deletions octobot_trading/exchanges/exchange_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from octobot_commons.logging.logging_util import get_logger

from octobot_trading.api.modes import init_trading_mode_config, create_trading_modes
from octobot_trading.constants import CONFIG_EXCHANGES, CONFIG_EXCHANGE_SANDBOXED
from octobot_trading.exchanges.exchange_manager import ExchangeManager
from octobot_trading.exchanges.exchanges import Exchanges
from octobot_trading.traders.trader import Trader
Expand All @@ -34,7 +35,6 @@ def __init__(self, config, exchange_name):
self.exchange_manager: ExchangeManager = ExchangeManager(self.config, self.exchange_name)

self._is_using_trading_modes: bool = True
self._is_exchange_manager_sandboxed: bool = False
self._matrix_id: str = None

self._trading_tentacles_path = CONFIG_TRADING_FILE_PATH
Expand All @@ -56,10 +56,6 @@ async def build(self):
if self._is_using_trading_modes:
self.exchange_manager.trading_modes = await self._build_modes()

# configure exchange
if not self.exchange_manager.is_backtesting:
self.exchange_manager.exchange.set_sandbox_mode(self._is_exchange_manager_sandboxed)

# add to global exchanges
Exchanges.instance().add_exchange(self.exchange_manager, self._matrix_id)

Expand Down Expand Up @@ -94,7 +90,8 @@ def is_backtesting(self, backtesting_files):
return self

def is_sandboxed(self, sandboxed: bool):
self._is_exchange_manager_sandboxed = sandboxed
self.exchange_manager.is_sandboxed = sandboxed or \
self.config[CONFIG_EXCHANGES][self.exchange_name][CONFIG_EXCHANGE_SANDBOXED]
return self

def is_simulated(self):
Expand Down
1 change: 1 addition & 0 deletions octobot_trading/exchanges/exchange_manager.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ cdef class ExchangeManager(Initializable):
cdef public bint is_trader_simulated
cdef public bint is_collecting
cdef public bint is_margin
cdef public bint is_sandboxed
cdef public bint has_websocket
cdef public bint exchange_only

Expand Down
6 changes: 5 additions & 1 deletion octobot_trading/exchanges/exchange_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ def __init__(self, config, exchange_class_string):
self.ignore_config: bool = False
self.is_collecting: bool = False
self.is_margin: bool = False
self.is_sandboxed: bool = False

# exchange_only is True when exchange channels are not required (therefore not created)
self.exchange_only: bool = False
Expand Down Expand Up @@ -163,7 +164,10 @@ async def _create_real_exchange(self):
if self.is_margin:
await self._search_and_create_margin_exchange()
else:
self.exchange = RestExchange(self.config, self.exchange_type, self)
self.exchange = RestExchange(config=self.config,
exchange_type=self.exchange_type,
exchange_manager=self,
is_sandboxed=self.is_sandboxed)

await self.exchange.initialize()

Expand Down
2 changes: 1 addition & 1 deletion octobot_trading/exchanges/margin/margin_exchange.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@
from octobot_trading.exchanges.rest_exchange cimport RestExchange

cdef class MarginExchange(RestExchange):
pass
cpdef list cleanup_positions_dict(self, list positions)
3 changes: 3 additions & 0 deletions octobot_trading/exchanges/margin/margin_exchange.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,6 @@ async def get_position_trades(self, position_id, symbol=None, since=None, limit=

async def get_position_status(self, position_id, symbol=None):
raise NotImplementedError("get_position_status is not implemented")

def cleanup_positions_dict(self, positions):
return positions
1 change: 1 addition & 0 deletions octobot_trading/exchanges/rest_exchange.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ from octobot_trading.exchanges.abstract_exchange cimport AbstractExchange

cdef class RestExchange(AbstractExchange):
cdef public bint is_authenticated
cdef public bint is_sandboxed

# balance additional info
cdef list info_list
Expand Down
22 changes: 15 additions & 7 deletions octobot_trading/exchanges/rest_exchange.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
from octobot_commons.enums import TimeFramesMinutes
from octobot_trading.constants import CONFIG_EXCHANGES, CONFIG_EXCHANGE_KEY, CONFIG_EXCHANGE_SECRET, \
CONFIG_EXCHANGE_PASSWORD, CONFIG_DEFAULT_FEES, CONFIG_PORTFOLIO_INFO, CONFIG_PORTFOLIO_FREE, CONFIG_PORTFOLIO_USED, \
CONFIG_PORTFOLIO_TOTAL
CONFIG_PORTFOLIO_TOTAL, CONFIG_EXCHANGE_SANDBOXED
from octobot_trading.enums import TraderOrderType, ExchangeConstantsMarketPropertyColumns, \
ExchangeConstantsOrderColumns as ecoc, TradeOrderSide
from octobot_trading.exchanges.abstract_exchange import AbstractExchange
Expand All @@ -40,14 +40,16 @@ class RestExchange(AbstractExchange):

CCXT_CLIENT_LOGIN_OPTIONS = {}

def __init__(self, config, exchange_type, exchange_manager):
def __init__(self, config, exchange_type, exchange_manager, is_sandboxed=False):
super().__init__(config, exchange_type, exchange_manager)
# We will need to create the rest client and fetch exchange config
self.is_authenticated = False
self.is_sandboxed = is_sandboxed
self.__create_client()

async def initialize_impl(self):
try:
self.set_sandbox_mode(self.is_sandboxed)
await self.client.load_markets()
except ExchangeNotAvailable as e:
self.logger.error(f"initialization impossible: {e}")
Expand Down Expand Up @@ -325,17 +327,23 @@ async def stop(self):
def get_pair_from_exchange(self, pair) -> str:
try:
return self.client.market(pair)["symbol"]
except ccxt.base.errors.BadSymbol:
self.logger.error(f"Failed to get market of {pair}")
return None
except BadSymbol:
try:
return self.client.markets_by_id[pair]["symbol"]
except KeyError:
self.logger.error(f"Failed to get market of {pair}")
return None

def get_split_pair_from_exchange(self, pair) -> (str, str):
try:
market_data: dict = self.client.market(pair)
return market_data["base"], market_data["quote"]
except BadSymbol:
self.logger.error(f"Failed to get market of {pair}")
return None, None
try:
return self.client.markets_by_id[pair]["base"], self.client.markets_by_id[pair]["quote"]
except KeyError:
self.logger.error(f"Failed to get market of {pair}")
return None, None

def get_exchange_pair(self, pair: str) -> str:
if pair in self.client.symbols:
Expand Down
2 changes: 1 addition & 1 deletion octobot_trading/producers/positions_updater.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ from octobot_trading.channels.positions cimport PositionsProducer


cdef class PositionsUpdater(PositionsProducer):
cdef dict _cleanup_positions_dict(self, dict positions)
pass
18 changes: 8 additions & 10 deletions octobot_trading/producers/positions_updater.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,14 @@ class PositionsUpdater(PositionsProducer):
POSITIONS_REFRESH_TIME = 11

async def start(self):
if not self._should_run():
return

while not self.should_stop and not self.channel.is_paused:
try:
positions: list = await self.channel.exchange_manager.exchange.get_open_position()
if positions:
await self.push(self._cleanup_positions_dict(positions))
await self.push(positions)
except NotSupported:
self.logger.warning(f"{self.channel.exchange_manager.exchange_name} is not supporting updates")
await self.pause()
Expand All @@ -41,17 +44,12 @@ async def start(self):

await asyncio.sleep(self.POSITIONS_REFRESH_TIME)

def _cleanup_positions_dict(self, positions):
for position in positions:
try:
# If exchange has not position id -> global position foreach symbol
if ExchangeConstantsOrderColumns.ID.value not in position:
position[ExchangeConstantsOrderColumns.ID.value] = position[ExchangeConstantsOrderColumns.SYMBOL.value]
except KeyError as e:
self.logger.error(f"Fail to cleanup position dict ({e})")
return positions
def _should_run(self) -> bool:
return self.channel.exchange_manager.is_margin

async def resume(self) -> None:
if not self._should_run():
return
await super().resume()
if not self.is_running:
await self.run()

0 comments on commit b8de43f

Please sign in to comment.