BLD: refinements to positions synchronization in live mode

This commit is contained in:
Frederic Fortier
2017-12-25 06:54:06 -05:00
parent 683f24b24f
commit 869ef8ec87
3 changed files with 30 additions and 52 deletions
+17 -31
View File
@@ -3,7 +3,6 @@ from abc import ABCMeta, abstractmethod, abstractproperty
from datetime import timedelta
from time import sleep
import ccxt
import numpy as np
import pandas as pd
from logbook import Logger
@@ -14,13 +13,12 @@ from catalyst.exchange.bundle_utils import get_start_dt, \
get_delta, get_periods, get_periods_range
from catalyst.exchange.exchange_bundle import ExchangeBundle
from catalyst.exchange.exchange_errors import MismatchingBaseCurrencies, \
BaseCurrencyNotFoundError, SymbolNotFoundOnExchange, \
SymbolNotFoundOnExchange, \
PricingDataNotLoadedError, \
NoDataAvailableOnExchange, NoValueForField, LastCandleTooEarlyError, \
TickerNotFoundError, BalanceNotFoundError, BalanceTooLowError
TickerNotFoundError, BalanceNotFoundError, NotEnoughCashError
from catalyst.exchange.exchange_utils import get_exchange_symbols, \
get_frequency, resample_history_df, has_bundle
from catalyst.utils.deprecate import deprecated
log = Logger('Exchange', level=LOG_LEVEL)
@@ -666,27 +664,12 @@ class Exchange:
)
if free < amount:
limit = amount * (1 - self.low_balance_threshold)
if free < limit:
raise BalanceTooLowError(
currency=currency,
exchange=self.name,
free=free,
amount=amount,
)
log.debug(
'detected lower balance for {} on {}: {} < {}, '
'updating position amount'.format(
currency, self.name, free, amount
)
)
return free, True
else:
return free, False
def sync_positions(self, positions, check_balances=False):
def sync_positions(self, positions, cash=None, check_balances=False):
"""
Update the portfolio cash and position balances based on the
latest ticker prices.
@@ -702,20 +685,23 @@ class Exchange:
"""
log.debug('synchronizing portfolio with exchange {}'.format(self.name))
cash = None
free_cash = 0.0
if check_balances:
balances = self.get_balances()
cash = balances[self.base_currency]['free'] \
if self.base_currency in balances else None
if cash is None:
raise BaseCurrencyNotFoundError(
base_currency=self.base_currency,
exchange=self.name,
if cash is not None:
free_cash, is_lower = self._check_low_balance(
currency=self.base_currency,
balances=balances,
amount=cash,
)
log.debug('found base currency balance: {}'.format(cash))
if is_lower:
raise NotEnoughCashError(
currency=self.base_currency,
exchange=self.name,
free=free_cash,
cash=cash,
)
positions_value = 0.0
if positions is not None:
@@ -750,7 +736,7 @@ class Exchange:
)
if is_lower:
log.debug(
log.warn(
'detected lower balance for {} on {}: {} < {}, '
'updating position amount'.format(
asset.symbol, self.name, free, position.amount
@@ -758,7 +744,7 @@ class Exchange:
)
position.amount = free
return cash, positions_value
return free_cash, positions_value
def order(self, asset, amount, style):
"""Place an order.
+4 -12
View File
@@ -10,6 +10,7 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import copy
import pickle
import signal
import sys
@@ -18,7 +19,6 @@ from os import listdir
from os.path import isfile, join
from time import sleep
import copy
import logbook
import pandas as pd
@@ -29,7 +29,7 @@ from catalyst.exchange.exchange_blotter import ExchangeBlotter
from catalyst.exchange.exchange_errors import (
ExchangeRequestError,
ExchangePortfolioDataError,
OrderTypeNotSupported, CashTooLowError)
OrderTypeNotSupported)
from catalyst.exchange.exchange_execution import ExchangeLimitOrder
from catalyst.exchange.exchange_utils import (
save_algo_object,
@@ -523,10 +523,9 @@ class ExchangeTradingAlgorithmLive(ExchangeTradingAlgorithmBase):
cash, positions_value = exchange.sync_positions(
positions=exchange_positions,
check_balances=check_balances,
cash=self.portfolio.cash,
)
if cash is not None:
total_cash += cash
total_cash += cash
total_positions_value += positions_value
# Applying modifications to the original positions
@@ -541,13 +540,6 @@ class ExchangeTradingAlgorithmLive(ExchangeTradingAlgorithmBase):
if not check_balances:
total_cash = self.portfolio.cash
elif total_cash < self.portfolio.cash:
raise CashTooLowError(
currency=self.exchanges[0].base_currency,
free=total_cash,
cash=self.portfolio.cash,
)
return total_cash, total_positions_value
except ExchangeRequestError as e:
+9 -9
View File
@@ -279,6 +279,15 @@ class NotEnoughCapitalError(ZiplineError):
).strip()
class NotEnoughCashError(ZiplineError):
msg = (
'Total {currency} amount on {exchange} is lower than the cash '
'reserved for this algo: {free} < {cash}. While trades can be made on '
'the exchange accounts outside of the algo, exchange must have enough '
'free {currency} to cover the algo cash.'
).strip()
class LastCandleTooEarlyError(ZiplineError):
msg = (
'The trade date of the last candle {last_traded} is before the '
@@ -306,12 +315,3 @@ class BalanceTooLowError(ZiplineError):
'add positions to hold a free amount greater than {amount}, or clean '
'the state of this algo and restart.'
).strip()
class CashTooLowError(ZiplineError):
msg = (
'Total {currency} amount on exchanges is lower than the cash reserved '
'for this algo: {free} < {cash}. While trades can be made on the '
'exchange accounts outside of the algo, they must not compromise '
'the required amount of free {currency}.'
).strip()