Skip to content

Commit

Permalink
[Portfolio] Manage delta updates
Browse files Browse the repository at this point in the history
  • Loading branch information
Herklos committed Sep 15, 2020
1 parent 4a712c9 commit 0f2fe8f
Show file tree
Hide file tree
Showing 9 changed files with 59 additions and 17 deletions.
4 changes: 2 additions & 2 deletions octobot_trading/api/profitability.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def get_current_portfolio_value(exchange_manager) -> float:

def get_current_holdings_values(exchange_manager) -> float:
return exchange_manager.exchange_personal_data.portfolio_manager.\
portfolio_profitability.get_current_holdings_values()
portfolio_value_holder.get_current_holdings_values()


def get_reference_market(config) -> str:
Expand All @@ -44,4 +44,4 @@ def get_reference_market(config) -> str:

def get_initializing_currencies_prices(exchange_manager) -> set:
return exchange_manager.exchange_personal_data.portfolio_manager.\
portfolio_profitability.initializing_symbol_prices
portfolio_value_holder.initializing_symbol_prices
10 changes: 5 additions & 5 deletions octobot_trading/channels/balance.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@


class BalanceProducer(ExchangeChannelProducer):
async def push(self, balance):
await self.perform(balance)
async def push(self, balance, is_diff_update=False):
await self.perform(balance, is_diff_update)

async def perform(self, balance):
async def perform(self, balance, is_diff_update=False):
try:
changed = await self.channel.exchange_manager.exchange_personal_data.handle_portfolio_update(
balance=balance, should_notify=False)
balance=balance, should_notify=False, is_diff_update=is_diff_update)
if changed:
await self.send(balance)
except CancelledError:
Expand Down Expand Up @@ -66,7 +66,7 @@ async def _update_portfolio_from_exchange(self, should_notify=False) -> bool:
"""
balance = await self.channel.exchange_manager.exchange.get_balance()
return await self.channel.exchange_manager.exchange_personal_data.handle_portfolio_update(
balance=balance, should_notify=should_notify)
balance=balance, should_notify=should_notify, is_diff_update=False)


class BalanceChannel(ExchangeChannel):
Expand Down
4 changes: 2 additions & 2 deletions octobot_trading/exchanges/data/exchange_personal_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,9 @@ async def initialize_impl(self):
f"{self.exchange.name} personal data disabled.")

# updates
async def handle_portfolio_update(self, balance, should_notify: bool = True) -> bool:
async def handle_portfolio_update(self, balance, should_notify: bool = True, is_diff_update=False) -> bool:
try:
changed: bool = self.portfolio_manager.handle_balance_update(balance)
changed: bool = self.portfolio_manager.handle_balance_update(balance, is_diff_update=is_diff_update)
if should_notify:
await get_chan(BALANCE_CHANNEL, self.exchange_manager.id).get_internal_producer().send(balance)
return changed
Expand Down
2 changes: 1 addition & 1 deletion octobot_trading/portfolios/portfolio.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ cdef class Portfolio(Initializable):
# public methods
cpdef double get_currency_portfolio(self, str currency, str portfolio_type=*)
cpdef double get_currency_from_given_portfolio(self, str currency, str portfolio_type=*)
cpdef bint update_portfolio_from_balance(self, dict balance)
cpdef bint update_portfolio_from_balance(self, dict balance, bint force_replace=*)
cpdef void update_portfolio_available(self, Order order, bint is_new_order=*)
cpdef void update_portfolio_from_filled_order(self, Order order)
cpdef void reset_portfolio_available(self, str reset_currency=*, object reset_quantity=*)
Expand Down
9 changes: 7 additions & 2 deletions octobot_trading/portfolios/portfolio.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,16 +66,21 @@ async def copy(self):
new_portfolio.portfolio = deepcopy(self.portfolio)
return new_portfolio

def update_portfolio_from_balance(self, balance):
def update_portfolio_from_balance(self, balance, force_replace=True):
"""
Update portfolio from a balance dict
:param balance: the portfolio dict
:param force_replace: force to update portfolio. Should be False when using deltas
:return: True if the portfolio has been updated
"""
if balance == self.portfolio:
# when the portfolio shouldn't be updated
return False
self.portfolio = {currency: self._parse_currency_balance(balance[currency]) for currency in balance}
new_balance = {currency: self._parse_currency_balance(balance[currency]) for currency in balance}
if force_replace:
self.portfolio = new_balance
else:
self.portfolio.update(new_balance)
self.logger.debug(f"Portfolio updated | {CURRENT_PORTFOLIO_STRING} {self.portfolio}")
return True

Expand Down
2 changes: 1 addition & 1 deletion octobot_trading/portfolios/portfolio_manager.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ cdef class PortfolioManager(Initializable):
cdef public PortfolioValueHolder portfolio_value_holder
cdef public Portfolio portfolio

cpdef bint handle_balance_update(self, dict balance)
cpdef bint handle_balance_update(self, dict balance, bint is_diff_update=*)
cpdef void clear(self)

cdef void _load_portfolio(self)
Expand Down
5 changes: 3 additions & 2 deletions octobot_trading/portfolios/portfolio_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,15 @@ async def initialize_impl(self):
"""
await self._reset_portfolio()

def handle_balance_update(self, balance):
def handle_balance_update(self, balance, is_diff_update=False):
"""
Handle a balance update request
:param balance: the new balance
:param is_diff_update: True when the update is a partial portfolio
:return: True if the portfolio was updated
"""
if self.trader.is_enabled and balance is not None:
return self.portfolio.update_portfolio_from_balance(balance)
return self.portfolio.update_portfolio_from_balance(balance, force_replace=not is_diff_update)
return False

async def handle_balance_update_from_order(self, order) -> bool:
Expand Down
4 changes: 2 additions & 2 deletions octobot_trading/portfolios/sub_portfolio.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ def __init__(self, config, trader, parent_portfolio, percent, is_relative=True):
super().__init__(config, trader)

# overwrite parent update_portfolio_balance
async def update_portfolio_from_balance(self, balance):
modified = self.parent_portfolio.update_portfolio_from_balance(balance)
def update_portfolio_from_balance(self, balance, force_replace=True):
modified = self.parent_portfolio.update_portfolio_from_balance(balance, force_replace=force_replace)
self.update_from_parent()
return modified

Expand Down
36 changes: 36 additions & 0 deletions tests/portfolios/test_portfolio.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,42 @@ async def test_update_portfolio_from_balance(backtesting_trader):
assert not portfolio_manager.portfolio.update_portfolio_from_balance(test_portfolio)


async def test_update_portfolio_from_balance_with_deltas(backtesting_trader):
config, exchange_manager, trader = backtesting_trader
portfolio_manager = exchange_manager.exchange_personal_data.portfolio_manager
test_portfolio = {"BTC": {PORTFOLIO_AVAILABLE: 1,
PORTFOLIO_TOTAL: 1}}

assert portfolio_manager.portfolio.update_portfolio_from_balance(test_portfolio, force_replace=False)
assert portfolio_manager.portfolio.portfolio == {
'BTC': {PORTFOLIO_AVAILABLE: 1, PORTFOLIO_TOTAL: 1},
'USDT': {PORTFOLIO_AVAILABLE: 1000, PORTFOLIO_TOTAL: 1000}
}

test_portfolio_2 = {"NANO": {PORTFOLIO_AVAILABLE: 1, PORTFOLIO_TOTAL: 2}}

assert portfolio_manager.portfolio.update_portfolio_from_balance(test_portfolio_2, force_replace=False)
assert portfolio_manager.portfolio.portfolio == {
'BTC': {PORTFOLIO_AVAILABLE: 1, PORTFOLIO_TOTAL: 1},
'USDT': {PORTFOLIO_AVAILABLE: 1000, PORTFOLIO_TOTAL: 1000},
'NANO': {PORTFOLIO_AVAILABLE: 1, PORTFOLIO_TOTAL: 2}
}

test_portfolio_3 = {"USDT": {PORTFOLIO_AVAILABLE: 250, PORTFOLIO_TOTAL: 500}}

assert portfolio_manager.portfolio.update_portfolio_from_balance(test_portfolio_3, force_replace=False)
assert portfolio_manager.portfolio.portfolio == {
'BTC': {PORTFOLIO_AVAILABLE: 1, PORTFOLIO_TOTAL: 1},
'USDT': {PORTFOLIO_AVAILABLE: 250, PORTFOLIO_TOTAL: 500},
'NANO': {PORTFOLIO_AVAILABLE: 1, PORTFOLIO_TOTAL: 2}
}

test_portfolio_4 = {"USDT": {PORTFOLIO_AVAILABLE: 100, PORTFOLIO_TOTAL: 100}}

assert portfolio_manager.portfolio.update_portfolio_from_balance(test_portfolio_4, force_replace=True)
assert portfolio_manager.portfolio.portfolio == test_portfolio_4


async def test_update_portfolio_available_from_order(backtesting_trader):
config, exchange_manager, trader = backtesting_trader
portfolio_manager = exchange_manager.exchange_personal_data.portfolio_manager
Expand Down

0 comments on commit 0f2fe8f

Please sign in to comment.