mirror of
https://github.com/wassname/catalyst.git
synced 2026-09-11 12:00:50 +08:00
DOC: updating the code docstrings
This commit is contained in:
+141
-58
@@ -1,5 +1,4 @@
|
|||||||
import abc
|
import abc
|
||||||
import re
|
|
||||||
from abc import ABCMeta, abstractmethod, abstractproperty
|
from abc import ABCMeta, abstractmethod, abstractproperty
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from time import sleep
|
from time import sleep
|
||||||
@@ -16,7 +15,7 @@ from catalyst.exchange.bundle_utils import get_start_dt, \
|
|||||||
from catalyst.exchange.exchange_bundle import ExchangeBundle
|
from catalyst.exchange.exchange_bundle import ExchangeBundle
|
||||||
from catalyst.exchange.exchange_errors import MismatchingBaseCurrencies, \
|
from catalyst.exchange.exchange_errors import MismatchingBaseCurrencies, \
|
||||||
InvalidOrderStyle, BaseCurrencyNotFoundError, SymbolNotFoundOnExchange, \
|
InvalidOrderStyle, BaseCurrencyNotFoundError, SymbolNotFoundOnExchange, \
|
||||||
InvalidHistoryFrequencyError, PricingDataNotLoadedError, \
|
PricingDataNotLoadedError, \
|
||||||
NoDataAvailableOnExchange
|
NoDataAvailableOnExchange
|
||||||
from catalyst.exchange.exchange_execution import ExchangeStopLimitOrder, \
|
from catalyst.exchange.exchange_execution import ExchangeStopLimitOrder, \
|
||||||
ExchangeLimitOrder, ExchangeStopOrder
|
ExchangeLimitOrder, ExchangeStopOrder
|
||||||
@@ -53,9 +52,11 @@ class Exchange:
|
|||||||
@property
|
@property
|
||||||
def portfolio(self):
|
def portfolio(self):
|
||||||
"""
|
"""
|
||||||
Return the Portfolio
|
The exchange portfolio
|
||||||
|
|
||||||
:return:
|
Returns
|
||||||
|
-------
|
||||||
|
ExchangePortfolio
|
||||||
"""
|
"""
|
||||||
if self._portfolio is None:
|
if self._portfolio is None:
|
||||||
self._portfolio = ExchangePortfolio(
|
self._portfolio = ExchangePortfolio(
|
||||||
@@ -75,9 +76,16 @@ class Exchange:
|
|||||||
|
|
||||||
def is_open(self, dt):
|
def is_open(self, dt):
|
||||||
"""
|
"""
|
||||||
Is the exchange open?
|
Is the exchange open
|
||||||
:param dt:
|
|
||||||
:return:
|
Parameters
|
||||||
|
----------
|
||||||
|
dt: Timestamp
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
bool
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# TODO: implement for each exchange.
|
# TODO: implement for each exchange.
|
||||||
return True
|
return True
|
||||||
@@ -90,7 +98,9 @@ class Exchange:
|
|||||||
The application will pause if the maximum requests per minute
|
The application will pause if the maximum requests per minute
|
||||||
permitted by the exchange is exceeded.
|
permitted by the exchange is exceeded.
|
||||||
|
|
||||||
:return boolean:
|
Returns
|
||||||
|
-------
|
||||||
|
bool
|
||||||
|
|
||||||
"""
|
"""
|
||||||
now = pd.Timestamp.utcnow()
|
now = pd.Timestamp.utcnow()
|
||||||
@@ -122,10 +132,16 @@ class Exchange:
|
|||||||
|
|
||||||
def get_symbol(self, asset):
|
def get_symbol(self, asset):
|
||||||
"""
|
"""
|
||||||
Get the exchange specific symbol of the given asset.
|
The the exchange specific symbol of the specified market.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
asset: TradingPair
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
str
|
||||||
|
|
||||||
:param asset: Asset
|
|
||||||
:return: symbol: str
|
|
||||||
"""
|
"""
|
||||||
symbol = None
|
symbol = None
|
||||||
|
|
||||||
@@ -143,17 +159,34 @@ class Exchange:
|
|||||||
"""
|
"""
|
||||||
Get a list of symbols corresponding to each given asset.
|
Get a list of symbols corresponding to each given asset.
|
||||||
|
|
||||||
:param assets: Asset[]
|
Parameters
|
||||||
:return:
|
----------
|
||||||
|
assets: list[TradingPair]
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
list[str]
|
||||||
|
|
||||||
"""
|
"""
|
||||||
symbols = []
|
symbols = []
|
||||||
|
|
||||||
for asset in assets:
|
for asset in assets:
|
||||||
symbols.append(self.get_symbol(asset))
|
symbols.append(self.get_symbol(asset))
|
||||||
|
|
||||||
return symbols
|
return symbols
|
||||||
|
|
||||||
def get_assets(self, symbols=None):
|
def get_assets(self, symbols=None):
|
||||||
|
"""
|
||||||
|
The list of markets for the specified symbols.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
symbols: list[str]
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
list[TradingPair]
|
||||||
|
|
||||||
|
"""
|
||||||
assets = []
|
assets = []
|
||||||
|
|
||||||
if symbols is not None:
|
if symbols is not None:
|
||||||
@@ -168,9 +201,16 @@ class Exchange:
|
|||||||
|
|
||||||
def get_asset(self, symbol):
|
def get_asset(self, symbol):
|
||||||
"""
|
"""
|
||||||
Find an Asset on the current exchange based on its Catalyst symbol
|
The market for the specified symbol.
|
||||||
:param symbol: the [target]_[base] currency pair symbol
|
|
||||||
:return: Asset
|
Parameters
|
||||||
|
----------
|
||||||
|
symbol: str
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
TradingPair
|
||||||
|
|
||||||
"""
|
"""
|
||||||
asset = None
|
asset = None
|
||||||
|
|
||||||
@@ -201,7 +241,6 @@ class Exchange:
|
|||||||
currency pair symbol. The universal symbol is contained in the
|
currency pair symbol. The universal symbol is contained in the
|
||||||
'symbol' attribute of each asset.
|
'symbol' attribute of each asset.
|
||||||
|
|
||||||
|
|
||||||
Notes
|
Notes
|
||||||
-----
|
-----
|
||||||
The sid of each asset is calculated based on a numeric hash of the
|
The sid of each asset is calculated based on a numeric hash of the
|
||||||
@@ -210,8 +249,8 @@ class Exchange:
|
|||||||
|
|
||||||
This method can be overridden if an exchange offers equivalent data
|
This method can be overridden if an exchange offers equivalent data
|
||||||
via its api.
|
via its api.
|
||||||
"""
|
|
||||||
|
|
||||||
|
"""
|
||||||
symbol_map = self.fetch_symbol_map()
|
symbol_map = self.fetch_symbol_map()
|
||||||
for exchange_symbol in symbol_map:
|
for exchange_symbol in symbol_map:
|
||||||
asset = symbol_map[exchange_symbol]
|
asset = symbol_map[exchange_symbol]
|
||||||
@@ -272,8 +311,10 @@ class Exchange:
|
|||||||
For each executed order found, create a transaction and apply to the
|
For each executed order found, create a transaction and apply to the
|
||||||
Portfolio.
|
Portfolio.
|
||||||
|
|
||||||
:return:
|
Returns
|
||||||
transactions: Transaction[]
|
-------
|
||||||
|
list[Transaction]
|
||||||
|
|
||||||
"""
|
"""
|
||||||
transactions = list()
|
transactions = list()
|
||||||
if self.portfolio.open_orders:
|
if self.portfolio.open_orders:
|
||||||
@@ -390,14 +431,20 @@ class Exchange:
|
|||||||
"""
|
"""
|
||||||
Get a series of field data for the specified candles.
|
Get a series of field data for the specified candles.
|
||||||
|
|
||||||
:param candles:
|
Parameters
|
||||||
:param start_dt:
|
----------
|
||||||
:param end_dt:
|
candles: list[dict[str, float]]
|
||||||
:param field:
|
start_dt: datetime
|
||||||
:param previous_value:
|
end_dt: datetime
|
||||||
:return:
|
data_frequency: str
|
||||||
"""
|
field: str
|
||||||
|
previous_value: float
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
Series
|
||||||
|
|
||||||
|
"""
|
||||||
dates = [candle['last_traded'] for candle in candles]
|
dates = [candle['last_traded'] for candle in candles]
|
||||||
values = [candle[field] for candle in candles]
|
values = [candle[field] for candle in candles]
|
||||||
series = pd.Series(values, index=dates)
|
series = pd.Series(values, index=dates)
|
||||||
@@ -430,10 +477,11 @@ class Exchange:
|
|||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
assets : list of catalyst.data.Asset objects
|
assets : list[TradingPair]
|
||||||
The assets whose data is desired.
|
The assets whose data is desired.
|
||||||
|
|
||||||
end_dt: not applicable to cryptocurrencies
|
end_dt: datetime
|
||||||
|
The date of the last bar
|
||||||
|
|
||||||
bar_count: int
|
bar_count: int
|
||||||
The number of bars desired.
|
The number of bars desired.
|
||||||
@@ -493,10 +541,11 @@ class Exchange:
|
|||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
assets : list of catalyst.data.Asset objects
|
assets : list[TradingPair]
|
||||||
The assets whose data is desired.
|
The assets whose data is desired.
|
||||||
|
|
||||||
end_dt: not applicable to cryptocurrencies
|
end_dt: datetime
|
||||||
|
The date of the last bar.
|
||||||
|
|
||||||
bar_count: int
|
bar_count: int
|
||||||
The number of bars desired.
|
The number of bars desired.
|
||||||
@@ -518,9 +567,10 @@ class Exchange:
|
|||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
A dataframe containing the requested data.
|
DataFrame
|
||||||
"""
|
A dataframe containing the requested data.
|
||||||
|
|
||||||
|
"""
|
||||||
freq, candle_size, unit, data_frequency = get_frequency(
|
freq, candle_size, unit, data_frequency = get_frequency(
|
||||||
frequency, data_frequency
|
frequency, data_frequency
|
||||||
)
|
)
|
||||||
@@ -591,7 +641,6 @@ class Exchange:
|
|||||||
Update the portfolio cash and position balances based on the
|
Update the portfolio cash and position balances based on the
|
||||||
latest ticker prices.
|
latest ticker prices.
|
||||||
|
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
log.debug('synchronizing portfolio with exchange {}'.format(self.name))
|
log.debug('synchronizing portfolio with exchange {}'.format(self.name))
|
||||||
balances = self.get_balances()
|
balances = self.get_balances()
|
||||||
@@ -635,16 +684,20 @@ class Exchange:
|
|||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
asset : Asset
|
asset : TradingPair
|
||||||
The asset that this order is for.
|
The asset that this order is for.
|
||||||
|
|
||||||
amount : int
|
amount : int
|
||||||
The amount of shares to order. If ``amount`` is positive, this is
|
The amount of shares to order. If ``amount`` is positive, this is
|
||||||
the number of shares to buy or cover. If ``amount`` is negative,
|
the number of shares to buy or cover. If ``amount`` is negative,
|
||||||
this is the number of shares to sell or short.
|
this is the number of shares to sell or short.
|
||||||
|
|
||||||
limit_price : float, optional
|
limit_price : float, optional
|
||||||
The limit price for the order.
|
The limit price for the order.
|
||||||
|
|
||||||
stop_price : float, optional
|
stop_price : float, optional
|
||||||
The stop price for the order.
|
The stop price for the order.
|
||||||
|
|
||||||
style : ExecutionStyle, optional
|
style : ExecutionStyle, optional
|
||||||
The execution style for the order.
|
The execution style for the order.
|
||||||
|
|
||||||
@@ -669,6 +722,7 @@ class Exchange:
|
|||||||
:class:`catalyst.finance.execution.ExecutionStyle`
|
:class:`catalyst.finance.execution.ExecutionStyle`
|
||||||
:func:`catalyst.api.order_value`
|
:func:`catalyst.api.order_value`
|
||||||
:func:`catalyst.api.order_percent`
|
:func:`catalyst.api.order_percent`
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if amount == 0:
|
if amount == 0:
|
||||||
log.warn('skipping order amount of 0')
|
log.warn('skipping order amount of 0')
|
||||||
@@ -718,8 +772,12 @@ class Exchange:
|
|||||||
@abstractmethod
|
@abstractmethod
|
||||||
def get_balances(self):
|
def get_balances(self):
|
||||||
"""
|
"""
|
||||||
Retrieve wallet balances for the exchange
|
Retrieve wallet balances for the exchange.
|
||||||
:return balances: A dict of currency => available balance
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
dict[TradingPair, float]
|
||||||
|
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -728,17 +786,25 @@ class Exchange:
|
|||||||
"""
|
"""
|
||||||
Place an order on the exchange.
|
Place an order on the exchange.
|
||||||
|
|
||||||
:param asset : Asset
|
Parameters
|
||||||
The asset that this order is for.
|
----------
|
||||||
:param amount : int
|
asset: TradingPair
|
||||||
|
The target market.
|
||||||
|
|
||||||
|
amount: float
|
||||||
The amount of shares to order. If ``amount`` is positive, this is
|
The amount of shares to order. If ``amount`` is positive, this is
|
||||||
the number of shares to buy or cover. If ``amount`` is negative,
|
the number of shares to buy or cover. If ``amount`` is negative,
|
||||||
this is the number of shares to sell or short.
|
this is the number of shares to sell or short.
|
||||||
:param style : ExecutionStyle
|
|
||||||
The execution style for the order.
|
is_buy: bool
|
||||||
:param is_buy: boolean
|
|
||||||
Is it a buy order?
|
Is it a buy order?
|
||||||
:return:
|
|
||||||
|
style: ExecutionStyle
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
Order
|
||||||
|
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -798,19 +864,27 @@ class Exchange:
|
|||||||
"""
|
"""
|
||||||
Retrieve OHLCV candles for the given assets
|
Retrieve OHLCV candles for the given assets
|
||||||
|
|
||||||
:param freq:
|
Parameters
|
||||||
|
----------
|
||||||
|
freq: str
|
||||||
The frequency alias per convention:
|
The frequency alias per convention:
|
||||||
http://pandas.pydata.org/pandas-docs/stable/timeseries.html#offset-aliases
|
http://pandas.pydata.org/pandas-docs/stable/timeseries.html#offset-aliases
|
||||||
:param assets: list[TradingPair]
|
|
||||||
|
assets: list[TradingPair]
|
||||||
The targeted assets.
|
The targeted assets.
|
||||||
:param bar_count:
|
|
||||||
|
bar_count: int
|
||||||
The number of bar desired. (default 1)
|
The number of bar desired. (default 1)
|
||||||
:param end_dt: datetime, optional
|
|
||||||
|
end_dt: datetime, optional
|
||||||
The last bar date.
|
The last bar date.
|
||||||
:param start_dt: datetime, optional
|
|
||||||
|
start_dt: datetime, optional
|
||||||
The first bar date.
|
The first bar date.
|
||||||
|
|
||||||
:return dict[TradingPair, dict[str, Object]]: OHLCV data
|
Returns
|
||||||
|
-------
|
||||||
|
dict[TradingPair, dict[str, Object]]
|
||||||
A dictionary of OHLCV candles. Each TradingPair instance is
|
A dictionary of OHLCV candles. Each TradingPair instance is
|
||||||
mapped to a list of dictionaries with this structure:
|
mapped to a list of dictionaries with this structure:
|
||||||
open: float
|
open: float
|
||||||
@@ -830,8 +904,14 @@ class Exchange:
|
|||||||
"""
|
"""
|
||||||
Retrieve current tick data for the given assets
|
Retrieve current tick data for the given assets
|
||||||
|
|
||||||
:param assets:
|
Parameters
|
||||||
:return:
|
----------
|
||||||
|
assets: list[TradingPair]
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
list[dict[str, float]
|
||||||
|
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -839,7 +919,6 @@ class Exchange:
|
|||||||
def get_account(self):
|
def get_account(self):
|
||||||
"""
|
"""
|
||||||
Retrieve the account parameters.
|
Retrieve the account parameters.
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -848,11 +927,15 @@ class Exchange:
|
|||||||
"""
|
"""
|
||||||
Retrieve the the orderbook for the given trading pair.
|
Retrieve the the orderbook for the given trading pair.
|
||||||
|
|
||||||
:param asset: TradingPair
|
Parameters
|
||||||
:param order_type: str
|
----------
|
||||||
|
asset: TradingPair
|
||||||
|
order_type: str
|
||||||
The type of orders: bid, ask or all
|
The type of orders: bid, ask or all
|
||||||
:param limit
|
limit: int
|
||||||
|
|
||||||
:return:
|
Returns
|
||||||
|
-------
|
||||||
|
list[dict[str, float]
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -127,7 +127,13 @@ class ExchangeTradingAlgorithmBase(TradingAlgorithm):
|
|||||||
"""
|
"""
|
||||||
Creates a dictionary representing the state of the tracker.
|
Creates a dictionary representing the state of the tracker.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
start_dt: datetime
|
||||||
|
end_dt: datetime
|
||||||
|
|
||||||
|
Notes
|
||||||
|
-----
|
||||||
I rewrote this in an attempt to better control the stats.
|
I rewrote this in an attempt to better control the stats.
|
||||||
I don't want things to happen magically through complex logic
|
I don't want things to happen magically through complex logic
|
||||||
pertaining to backtesting.
|
pertaining to backtesting.
|
||||||
@@ -296,6 +302,18 @@ class ExchangeTradingAlgorithmLive(ExchangeTradingAlgorithmBase):
|
|||||||
self.exchange.minute_reader = BcolzMinuteBarReader(root)
|
self.exchange.minute_reader = BcolzMinuteBarReader(root)
|
||||||
|
|
||||||
def signal_handler(self, signal, frame):
|
def signal_handler(self, signal, frame):
|
||||||
|
"""
|
||||||
|
Handles the keyboard interruption signal.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
signal
|
||||||
|
frame
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
|
||||||
|
"""
|
||||||
self.is_running = False
|
self.is_running = False
|
||||||
|
|
||||||
if self._analyze is None:
|
if self._analyze is None:
|
||||||
@@ -384,7 +402,11 @@ class ExchangeTradingAlgorithmLive(ExchangeTradingAlgorithmBase):
|
|||||||
"""
|
"""
|
||||||
We skip the entire performance tracker business and update the
|
We skip the entire performance tracker business and update the
|
||||||
portfolio directly.
|
portfolio directly.
|
||||||
:return:
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
ExchangePortfolio
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# TODO: build cumulative portfolio
|
# TODO: build cumulative portfolio
|
||||||
return self.perf_tracker.get_portfolio(False)
|
return self.perf_tracker.get_portfolio(False)
|
||||||
@@ -450,6 +472,17 @@ class ExchangeTradingAlgorithmLive(ExchangeTradingAlgorithmBase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def add_pnl_stats(self, period_stats):
|
def add_pnl_stats(self, period_stats):
|
||||||
|
"""
|
||||||
|
Save p&l stats.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
period_stats
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
|
||||||
|
"""
|
||||||
starting = period_stats['starting_cash']
|
starting = period_stats['starting_cash']
|
||||||
current = period_stats['portfolio_value']
|
current = period_stats['portfolio_value']
|
||||||
appreciation = (current / starting) - 1
|
appreciation = (current / starting) - 1
|
||||||
@@ -466,6 +499,17 @@ class ExchangeTradingAlgorithmLive(ExchangeTradingAlgorithmBase):
|
|||||||
save_algo_df(self.algo_namespace, 'pnl_stats', self.pnl_stats)
|
save_algo_df(self.algo_namespace, 'pnl_stats', self.pnl_stats)
|
||||||
|
|
||||||
def add_custom_signals_stats(self, period_stats):
|
def add_custom_signals_stats(self, period_stats):
|
||||||
|
"""
|
||||||
|
Save custom signals stats.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
period_stats
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
|
||||||
|
"""
|
||||||
log.debug('adding custom signals stats: {}'.format(self.recorded_vars))
|
log.debug('adding custom signals stats: {}'.format(self.recorded_vars))
|
||||||
df = pd.DataFrame(
|
df = pd.DataFrame(
|
||||||
data=[self.recorded_vars],
|
data=[self.recorded_vars],
|
||||||
@@ -477,6 +521,17 @@ class ExchangeTradingAlgorithmLive(ExchangeTradingAlgorithmBase):
|
|||||||
self.custom_signals_stats)
|
self.custom_signals_stats)
|
||||||
|
|
||||||
def add_exposure_stats(self, period_stats):
|
def add_exposure_stats(self, period_stats):
|
||||||
|
"""
|
||||||
|
Save exposure stats.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
period_stats
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
|
||||||
|
"""
|
||||||
data = dict(
|
data = dict(
|
||||||
long_exposure=period_stats['long_exposure'],
|
long_exposure=period_stats['long_exposure'],
|
||||||
base_currency=period_stats['ending_cash']
|
base_currency=period_stats['ending_cash']
|
||||||
@@ -493,6 +548,14 @@ class ExchangeTradingAlgorithmLive(ExchangeTradingAlgorithmBase):
|
|||||||
self.exposure_stats)
|
self.exposure_stats)
|
||||||
|
|
||||||
def handle_data(self, data):
|
def handle_data(self, data):
|
||||||
|
"""
|
||||||
|
Wrapper around the handle_data method of each algo.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
data
|
||||||
|
|
||||||
|
"""
|
||||||
if not self.is_running:
|
if not self.is_running:
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -619,15 +682,16 @@ class ExchangeTradingAlgorithmLive(ExchangeTradingAlgorithmBase):
|
|||||||
The cumulative portfolio does not contain open orders but exchange
|
The cumulative portfolio does not contain open orders but exchange
|
||||||
portfolios do.
|
portfolios do.
|
||||||
|
|
||||||
:param asset: TradingPair
|
Parameters
|
||||||
:param amount: float
|
----------
|
||||||
:param limit_price: float
|
asset: TradingPair
|
||||||
:param stop_price: float
|
amount: float
|
||||||
:param style: Style
|
limit_price: float
|
||||||
:return order: Order
|
stop_price: float
|
||||||
|
style: Style
|
||||||
|
order: Order
|
||||||
The catalyst order object or None
|
The catalyst order object or None
|
||||||
"""
|
"""
|
||||||
|
|
||||||
amount, style = self._calculate_order(asset, amount,
|
amount, style = self._calculate_order(asset, amount,
|
||||||
limit_price, stop_price,
|
limit_price, stop_price,
|
||||||
style)
|
style)
|
||||||
@@ -689,15 +753,53 @@ class ExchangeTradingAlgorithmLive(ExchangeTradingAlgorithmBase):
|
|||||||
'get_open_orders. Use `asset` instead.')
|
'get_open_orders. Use `asset` instead.')
|
||||||
@api_method
|
@api_method
|
||||||
def get_open_orders(self, asset=None):
|
def get_open_orders(self, asset=None):
|
||||||
|
"""Retrieve all of the current open orders.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
asset : Asset
|
||||||
|
If passed and not None, return only the open orders for the given
|
||||||
|
asset instead of all open orders.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
open_orders : dict[list[Order]] or list[Order]
|
||||||
|
If no asset is passed this will return a dict mapping Assets
|
||||||
|
to a list containing all the open orders for the asset.
|
||||||
|
If an asset is passed then this will return a list of the open
|
||||||
|
orders for this asset.
|
||||||
|
"""
|
||||||
return self._get_open_orders(asset)
|
return self._get_open_orders(asset)
|
||||||
|
|
||||||
@api_method
|
@api_method
|
||||||
def get_order(self, order_id, exchange_name):
|
def get_order(self, order_id, exchange_name):
|
||||||
|
"""Lookup an order based on the order id returned from one of the
|
||||||
|
order functions.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
order_id : str
|
||||||
|
The unique identifier for the order.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
order : Order
|
||||||
|
The order object.
|
||||||
|
execution_price: float
|
||||||
|
The execution price per share of the order
|
||||||
|
"""
|
||||||
exchange = self.exchanges[exchange_name]
|
exchange = self.exchanges[exchange_name]
|
||||||
return exchange.get_order(order_id)
|
return exchange.get_order(order_id)
|
||||||
|
|
||||||
@api_method
|
@api_method
|
||||||
def cancel_order(self, order_param, exchange_name):
|
def cancel_order(self, order_param, exchange_name):
|
||||||
|
"""Cancel an open order.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
order_param : str or Order
|
||||||
|
The order_id or order object to cancel.
|
||||||
|
"""
|
||||||
exchange = self.exchanges[exchange_name]
|
exchange = self.exchanges[exchange_name]
|
||||||
|
|
||||||
order_id = order_param
|
order_id = order_param
|
||||||
|
|||||||
@@ -39,17 +39,25 @@ class BcolzExchangeBarReader(BcolzMinuteBarReader):
|
|||||||
return self._data_frequency
|
return self._data_frequency
|
||||||
|
|
||||||
def load_raw_arrays(self, fields, start_dt, end_dt, sids):
|
def load_raw_arrays(self, fields, start_dt, end_dt, sids):
|
||||||
|
"""
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
fields : list of str
|
||||||
|
'open', 'high', 'low', 'close', or 'volume'
|
||||||
|
start_dt: Timestamp
|
||||||
|
Beginning of the window range.
|
||||||
|
end_dt: Timestamp
|
||||||
|
End of the window range.
|
||||||
|
sids : list of int
|
||||||
|
The asset identifiers in the window.
|
||||||
|
|
||||||
# if self._data_frequency == 'minute':
|
Returns
|
||||||
# return super(BcolzExchangeBarReader, self) \
|
-------
|
||||||
# .load_raw_arrays(fields, start_dt, end_dt, sids)
|
list of np.ndarray
|
||||||
#
|
A list with an entry per field of ndarrays with shape
|
||||||
# else:
|
(minutes in range, sids) with a dtype of float64, containing the
|
||||||
# return self._load_daily_raw_arrays(fields, start_dt, end_dt, sids)
|
values for the respective field over start and end dt range.
|
||||||
|
"""
|
||||||
return self._load_raw_arrays(fields, start_dt, end_dt, sids)
|
|
||||||
|
|
||||||
def _load_raw_arrays(self, fields, start_dt, end_dt, sids):
|
|
||||||
start_idx = self._find_position_of_minute(start_dt)
|
start_idx = self._find_position_of_minute(start_dt)
|
||||||
end_idx = self._find_position_of_minute(end_dt)
|
end_idx = self._find_position_of_minute(end_dt)
|
||||||
|
|
||||||
|
|||||||
@@ -59,7 +59,10 @@ class ExchangeBundle:
|
|||||||
"""
|
"""
|
||||||
Get a data writer object, either a new object or from cache
|
Get a data writer object, either a new object or from cache
|
||||||
|
|
||||||
:return: BcolzMinuteBarReader or BcolzDailyBarReader
|
Returns
|
||||||
|
-------
|
||||||
|
BcolzMinuteBarReader | BcolzDailyBarReader
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if path is None:
|
if path is None:
|
||||||
root = get_exchange_folder(self.exchange.name)
|
root = get_exchange_folder(self.exchange.name)
|
||||||
@@ -88,7 +91,10 @@ class ExchangeBundle:
|
|||||||
"""
|
"""
|
||||||
Get a data writer object, either a new object or from cache
|
Get a data writer object, either a new object or from cache
|
||||||
|
|
||||||
:return: BcolzMinuteBarWriter or BcolzDailyBarWriter
|
Returns
|
||||||
|
-------
|
||||||
|
BcolzMinuteBarWriter | BcolzDailyBarWriter
|
||||||
|
|
||||||
"""
|
"""
|
||||||
root = get_exchange_folder(self.exchange.name)
|
root = get_exchange_folder(self.exchange.name)
|
||||||
path = BUNDLE_NAME_TEMPLATE.format(
|
path = BUNDLE_NAME_TEMPLATE.format(
|
||||||
@@ -144,13 +150,19 @@ class ExchangeBundle:
|
|||||||
If the data exists, the chunk ingestion is complete.
|
If the data exists, the chunk ingestion is complete.
|
||||||
If any data is missing we ingest the data.
|
If any data is missing we ingest the data.
|
||||||
|
|
||||||
:param assets: list[TradingPair]
|
Parameters
|
||||||
|
----------
|
||||||
|
assets: list[TradingPair]
|
||||||
The assets is scope.
|
The assets is scope.
|
||||||
:param start_dt:
|
start_dt: datetime
|
||||||
The chunk start date.
|
The chunk start date.
|
||||||
:param end_dt:
|
end_dt: datetime
|
||||||
The chunk end date.
|
The chunk end date.
|
||||||
:return: list[TradingPair]
|
data_frequency: str
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
list[TradingPair]
|
||||||
The assets missing from the bundle
|
The assets missing from the bundle
|
||||||
"""
|
"""
|
||||||
reader = self.get_reader(data_frequency)
|
reader = self.get_reader(data_frequency)
|
||||||
@@ -164,13 +176,6 @@ class ExchangeBundle:
|
|||||||
return missing_assets
|
return missing_assets
|
||||||
|
|
||||||
def _write(self, data, writer, data_frequency):
|
def _write(self, data, writer, data_frequency):
|
||||||
"""
|
|
||||||
Write data to the writer
|
|
||||||
|
|
||||||
:param df:
|
|
||||||
:param writer:
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
try:
|
try:
|
||||||
writer.write(
|
writer.write(
|
||||||
data=data,
|
data=data,
|
||||||
@@ -195,6 +200,20 @@ class ExchangeBundle:
|
|||||||
)
|
)
|
||||||
|
|
||||||
def get_calendar_periods_range(self, start_dt, end_dt, data_frequency):
|
def get_calendar_periods_range(self, start_dt, end_dt, data_frequency):
|
||||||
|
"""
|
||||||
|
Get a list of dates for the specified range.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
start_dt: datetime
|
||||||
|
end_dt: datetime
|
||||||
|
data_frequency: str
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
list[datetime]
|
||||||
|
|
||||||
|
"""
|
||||||
return self.calendar.minutes_in_range(start_dt, end_dt) \
|
return self.calendar.minutes_in_range(start_dt, end_dt) \
|
||||||
if data_frequency == 'minute' \
|
if data_frequency == 'minute' \
|
||||||
else self.calendar.sessions_in_range(start_dt, end_dt)
|
else self.calendar.sessions_in_range(start_dt, end_dt)
|
||||||
@@ -204,13 +223,14 @@ class ExchangeBundle:
|
|||||||
"""
|
"""
|
||||||
Ingest a DataFrame of OHLCV data for a given market.
|
Ingest a DataFrame of OHLCV data for a given market.
|
||||||
|
|
||||||
:param ohlcv_df:
|
Parameters
|
||||||
:param data_frequency:
|
----------
|
||||||
:param asset:
|
ohlcv_df: DataFrame
|
||||||
:param writer:
|
data_frequency: str
|
||||||
:param path:
|
asset: TradingPair
|
||||||
:param empty_rows_behavior:
|
writer:
|
||||||
:return:
|
empty_rows_behavior: str
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if empty_rows_behavior is not 'ignore':
|
if empty_rows_behavior is not 'ignore':
|
||||||
nan_rows = ohlcv_df[ohlcv_df.isnull().T.any().T].index
|
nan_rows = ohlcv_df[ohlcv_df.isnull().T.any().T].index
|
||||||
@@ -269,14 +289,16 @@ class ExchangeBundle:
|
|||||||
"""
|
"""
|
||||||
Merge a ctable bundle chunk into the main bundle for the exchange.
|
Merge a ctable bundle chunk into the main bundle for the exchange.
|
||||||
|
|
||||||
:param asset: TradingPair
|
Parameters
|
||||||
:param data_frequency: str
|
----------
|
||||||
:param period: str
|
asset: TradingPair
|
||||||
:param writer:
|
data_frequency: str
|
||||||
:param empty_rows_behavior: str
|
period: str
|
||||||
|
writer:
|
||||||
|
empty_rows_behavior: str
|
||||||
Ensure that the bundle does not have any missing data.
|
Ensure that the bundle does not have any missing data.
|
||||||
|
|
||||||
:param cleanup: bool
|
cleanup: bool
|
||||||
Remove the temp bundle directory after ingestion.
|
Remove the temp bundle directory after ingestion.
|
||||||
|
|
||||||
:return:
|
:return:
|
||||||
@@ -331,13 +353,19 @@ class ExchangeBundle:
|
|||||||
|
|
||||||
def get_adj_dates(self, start, end, assets, data_frequency):
|
def get_adj_dates(self, start, end, assets, data_frequency):
|
||||||
"""
|
"""
|
||||||
Contains a date range to the trading availability of the specified pairs.
|
Contains a date range to the trading availability of the specified
|
||||||
|
markets.
|
||||||
|
|
||||||
:param start:
|
Parameters
|
||||||
:param end:
|
----------
|
||||||
:param assets:
|
start: datetime
|
||||||
:param data_frequency:
|
end: datetime
|
||||||
:return:
|
assets: list[TradingPair]
|
||||||
|
data_frequency: str
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
datetime, datetime
|
||||||
"""
|
"""
|
||||||
earliest_trade = None
|
earliest_trade = None
|
||||||
last_entry = None
|
last_entry = None
|
||||||
@@ -380,11 +408,17 @@ class ExchangeBundle:
|
|||||||
Split a price data request into chunks corresponding to individual
|
Split a price data request into chunks corresponding to individual
|
||||||
bundles.
|
bundles.
|
||||||
|
|
||||||
:param assets:
|
Parameters
|
||||||
:param data_frequency:
|
----------
|
||||||
:param start_dt:
|
assets: list[TradingPair]
|
||||||
:param end_dt:
|
data_frequency: str
|
||||||
:return:
|
start_dt: datetime
|
||||||
|
end_dt: datetime
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
dict[TradingPair, list[dict(str, Object]]]
|
||||||
|
|
||||||
"""
|
"""
|
||||||
reader = self.get_reader(data_frequency)
|
reader = self.get_reader(data_frequency)
|
||||||
|
|
||||||
@@ -456,10 +490,12 @@ class ExchangeBundle:
|
|||||||
"""
|
"""
|
||||||
Determine if data is missing from the bundle and attempt to ingest it.
|
Determine if data is missing from the bundle and attempt to ingest it.
|
||||||
|
|
||||||
:param assets:
|
Parameters
|
||||||
:param start_dt:
|
----------
|
||||||
:param end_dt:
|
assets: list[TradingPair]
|
||||||
:return:
|
start_dt: datetime
|
||||||
|
end_dt: datetime
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if start_dt is None:
|
if start_dt is None:
|
||||||
@@ -538,15 +574,18 @@ class ExchangeBundle:
|
|||||||
exclude_symbols=None, start=None, end=None,
|
exclude_symbols=None, start=None, end=None,
|
||||||
show_progress=True, environ=os.environ):
|
show_progress=True, environ=os.environ):
|
||||||
"""
|
"""
|
||||||
|
Inject data based on specified parameters.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
data_frequency: str
|
||||||
|
include_symbols: str
|
||||||
|
exclude_symbols: str
|
||||||
|
start: datetime
|
||||||
|
end: datetime
|
||||||
|
show_progress: bool
|
||||||
|
environ:
|
||||||
|
|
||||||
:param data_frequency:
|
|
||||||
:param include_symbols:
|
|
||||||
:param exclude_symbols:
|
|
||||||
:param start:
|
|
||||||
:param end:
|
|
||||||
:param show_progress:
|
|
||||||
:param environ:
|
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
assets = self.get_assets(include_symbols, exclude_symbols)
|
assets = self.get_assets(include_symbols, exclude_symbols)
|
||||||
|
|
||||||
@@ -562,16 +601,22 @@ class ExchangeBundle:
|
|||||||
data_frequency, # type: str
|
data_frequency, # type: str
|
||||||
algo_end_dt=None # type: Timestamp
|
algo_end_dt=None # type: Timestamp
|
||||||
):
|
):
|
||||||
# type: (...) -> Dict[str, Series]
|
|
||||||
"""
|
"""
|
||||||
Retrieve price data history, ingest missing data.
|
Retrieve price data history, ingest missing data.
|
||||||
|
|
||||||
:param assets:
|
Parameters
|
||||||
:param end_dt:
|
----------
|
||||||
:param bar_count:
|
assets: list[TradingPair]
|
||||||
:param field:
|
end_dt: datetime
|
||||||
:param data_frequency:
|
bar_count: int
|
||||||
:return:
|
field: str
|
||||||
|
data_frequency: str
|
||||||
|
algo_end_dt: datetime
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
Series
|
||||||
|
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
series = self.get_history_window_series(
|
series = self.get_history_window_series(
|
||||||
|
|||||||
@@ -1,16 +1,3 @@
|
|||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
# you may not use this file except in compliance with the License.
|
|
||||||
# You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
# 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 abc
|
import abc
|
||||||
from time import sleep
|
from time import sleep
|
||||||
|
|
||||||
@@ -238,6 +225,25 @@ class DataPortalExchangeLive(DataPortalExchangeBase):
|
|||||||
field,
|
field,
|
||||||
data_frequency,
|
data_frequency,
|
||||||
ffill=True):
|
ffill=True):
|
||||||
|
"""
|
||||||
|
Fetching price history window from the exchange.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
exchange: Exchange
|
||||||
|
assets: list[TradingPair]
|
||||||
|
end_dt: datetime
|
||||||
|
bar_count: int
|
||||||
|
frequency: str
|
||||||
|
field: str
|
||||||
|
data_frequency: str
|
||||||
|
ffill: bool
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
DataFrame
|
||||||
|
|
||||||
|
"""
|
||||||
df = exchange.get_history_window(
|
df = exchange.get_history_window(
|
||||||
assets,
|
assets,
|
||||||
end_dt,
|
end_dt,
|
||||||
@@ -250,6 +256,22 @@ class DataPortalExchangeLive(DataPortalExchangeBase):
|
|||||||
|
|
||||||
def get_exchange_spot_value(self, exchange, assets, field, dt,
|
def get_exchange_spot_value(self, exchange, assets, field, dt,
|
||||||
data_frequency):
|
data_frequency):
|
||||||
|
"""
|
||||||
|
A spot value for the exchange.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
exchange: Exchange
|
||||||
|
assets: list[TradingPair]
|
||||||
|
field: str
|
||||||
|
dt: datetime
|
||||||
|
data_frequency: str
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
float
|
||||||
|
|
||||||
|
"""
|
||||||
exchange_spot_values = exchange.get_spot_value(
|
exchange_spot_values = exchange.get_spot_value(
|
||||||
assets, field, dt, data_frequency)
|
assets, field, dt, data_frequency)
|
||||||
|
|
||||||
@@ -288,18 +310,21 @@ class DataPortalExchangeBacktest(DataPortalExchangeBase):
|
|||||||
"""
|
"""
|
||||||
Fetching price history window from the exchange bundle.
|
Fetching price history window from the exchange bundle.
|
||||||
|
|
||||||
Using a try... except approach to minimize reads most of the time,
|
Parameters
|
||||||
when the data exists.
|
----------
|
||||||
|
exchange: Exchange
|
||||||
|
assets: list[TradingPair]
|
||||||
|
end_dt: datetime
|
||||||
|
bar_count: int
|
||||||
|
frequency: str
|
||||||
|
field: str
|
||||||
|
data_frequency: str
|
||||||
|
ffill: bool
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
DataFrame
|
||||||
|
|
||||||
:param exchange:
|
|
||||||
:param assets:
|
|
||||||
:param end_dt:
|
|
||||||
:param bar_count:
|
|
||||||
:param frequency:
|
|
||||||
:param field:
|
|
||||||
:param data_frequency:
|
|
||||||
:param ffill:
|
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
bundle = self.exchange_bundles[exchange.name] # type: ExchangeBundle
|
bundle = self.exchange_bundles[exchange.name] # type: ExchangeBundle
|
||||||
|
|
||||||
@@ -321,26 +346,30 @@ class DataPortalExchangeBacktest(DataPortalExchangeBase):
|
|||||||
return df
|
return df
|
||||||
|
|
||||||
def get_exchange_spot_value(self,
|
def get_exchange_spot_value(self,
|
||||||
exchange, # type: Exchange
|
exchange,
|
||||||
assets, # type: List[TradingPair]
|
assets,
|
||||||
field, # type: str
|
field,
|
||||||
dt, # type: Timestamp
|
dt,
|
||||||
data_frequency # type: str
|
data_frequency
|
||||||
):
|
):
|
||||||
# type: (...) -> float
|
|
||||||
"""
|
"""
|
||||||
A spot value for the exchange bundle. Try to ingest data if not in
|
A spot value for the exchange bundle. Try to ingest data if not in
|
||||||
the bundle.
|
the bundle.
|
||||||
|
|
||||||
:param exchange:
|
Parameters
|
||||||
:param assets:
|
----------
|
||||||
:param field:
|
exchange: Exchange
|
||||||
:param dt:
|
assets: list[TradingPair]
|
||||||
:param data_frequency:
|
field: str
|
||||||
:return:
|
dt: datetime
|
||||||
|
data_frequency: str
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
float
|
||||||
|
|
||||||
"""
|
"""
|
||||||
bundle = self.exchange_bundles[exchange.name]
|
bundle = self.exchange_bundles[exchange.name]
|
||||||
|
|
||||||
if data_frequency == 'daily':
|
if data_frequency == 'daily':
|
||||||
dt = dt.floor('1D')
|
dt = dt.floor('1D')
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -4,9 +4,16 @@ from catalyst.finance.execution import LimitOrder, StopOrder, StopLimitOrder
|
|||||||
class ExchangeLimitOrder(LimitOrder):
|
class ExchangeLimitOrder(LimitOrder):
|
||||||
def get_limit_price(self, is_buy):
|
def get_limit_price(self, is_buy):
|
||||||
"""
|
"""
|
||||||
We may be trading Satoshis with 8 decimals, we cannot round numbers
|
We may be trading Satoshis with 8 decimals, we cannot round numbers.
|
||||||
:param is_buy:
|
|
||||||
:return:
|
Parameters
|
||||||
|
----------
|
||||||
|
is_buy: bool
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
float
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return self.limit_price
|
return self.limit_price
|
||||||
|
|
||||||
@@ -14,9 +21,16 @@ class ExchangeLimitOrder(LimitOrder):
|
|||||||
class ExchangeStopOrder(StopOrder):
|
class ExchangeStopOrder(StopOrder):
|
||||||
def get_stop_price(self, is_buy):
|
def get_stop_price(self, is_buy):
|
||||||
"""
|
"""
|
||||||
We may be trading Satoshis with 8 decimals, we cannot round numbers
|
We may be trading Satoshis with 8 decimals, we cannot round numbers.
|
||||||
:param is_buy:
|
|
||||||
:return:
|
Parameters
|
||||||
|
----------
|
||||||
|
is_buy: bool
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
float
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return self.stop_price
|
return self.stop_price
|
||||||
|
|
||||||
@@ -24,16 +38,30 @@ class ExchangeStopOrder(StopOrder):
|
|||||||
class ExchangeStopLimitOrder(StopLimitOrder):
|
class ExchangeStopLimitOrder(StopLimitOrder):
|
||||||
def get_limit_price(self, is_buy):
|
def get_limit_price(self, is_buy):
|
||||||
"""
|
"""
|
||||||
We may be trading Satoshis with 8 decimals, we cannot round numbers
|
We may be trading Satoshis with 8 decimals, we cannot round numbers.
|
||||||
:param is_buy:
|
|
||||||
:return:
|
Parameters
|
||||||
|
----------
|
||||||
|
is_buy: bool
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
float
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return self.limit_price
|
return self.limit_price
|
||||||
|
|
||||||
def get_stop_price(self, is_buy):
|
def get_stop_price(self, is_buy):
|
||||||
"""
|
"""
|
||||||
We may be trading Satoshis with 8 decimals, we cannot round numbers
|
We may be trading Satoshis with 8 decimals, we cannot round numbers.
|
||||||
:param is_buy:
|
|
||||||
:return:
|
Parameters
|
||||||
|
----------
|
||||||
|
is_buy: bool
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
float
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return self.stop_price
|
return self.stop_price
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ from logbook import Logger
|
|||||||
|
|
||||||
from catalyst.constants import LOG_LEVEL
|
from catalyst.constants import LOG_LEVEL
|
||||||
from catalyst.protocol import Portfolio, Positions, Position
|
from catalyst.protocol import Portfolio, Positions, Position
|
||||||
|
from catalyst.utils.deprecate import deprecated
|
||||||
|
|
||||||
log = Logger('ExchangePortfolio', level=LOG_LEVEL)
|
log = Logger('ExchangePortfolio', level=LOG_LEVEL)
|
||||||
|
|
||||||
@@ -29,10 +30,15 @@ class ExchangePortfolio(Portfolio):
|
|||||||
self.positions_value = 0.0
|
self.positions_value = 0.0
|
||||||
self.open_orders = dict()
|
self.open_orders = dict()
|
||||||
|
|
||||||
def calculate_pnl(self):
|
|
||||||
log.debug('calculating pnl')
|
|
||||||
|
|
||||||
def create_order(self, order):
|
def create_order(self, order):
|
||||||
|
"""
|
||||||
|
Create an open order and store in memory.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
order: Order
|
||||||
|
|
||||||
|
"""
|
||||||
log.debug('creating order {}'.format(order.id))
|
log.debug('creating order {}'.format(order.id))
|
||||||
self.open_orders[order.id] = order
|
self.open_orders[order.id] = order
|
||||||
|
|
||||||
@@ -47,6 +53,18 @@ class ExchangePortfolio(Portfolio):
|
|||||||
log.debug('open order added to portfolio')
|
log.debug('open order added to portfolio')
|
||||||
|
|
||||||
def execute_order(self, order, transaction):
|
def execute_order(self, order, transaction):
|
||||||
|
"""
|
||||||
|
Update the open orders and positions to apply an executed order.
|
||||||
|
|
||||||
|
Unlike with backtesting, we do not need to add slippage and fees.
|
||||||
|
The executed price includes transaction fees.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
order: Order
|
||||||
|
transaction: Transaction
|
||||||
|
|
||||||
|
"""
|
||||||
log.debug('executing order {}'.format(order.id))
|
log.debug('executing order {}'.format(order.id))
|
||||||
del self.open_orders[order.id]
|
del self.open_orders[order.id]
|
||||||
|
|
||||||
@@ -71,7 +89,9 @@ class ExchangePortfolio(Portfolio):
|
|||||||
|
|
||||||
log.debug('updated portfolio with executed order')
|
log.debug('updated portfolio with executed order')
|
||||||
|
|
||||||
|
@deprecated
|
||||||
def execute_transaction(self, transaction):
|
def execute_transaction(self, transaction):
|
||||||
|
# TODO: almost duplicate of execute_order. Not sure why Poloniex needs this.
|
||||||
log.debug('executing transaction {}'.format(transaction.order_id))
|
log.debug('executing transaction {}'.format(transaction.order_id))
|
||||||
|
|
||||||
order_position = self.positions[transaction.asset] \
|
order_position = self.positions[transaction.asset] \
|
||||||
@@ -96,6 +116,14 @@ class ExchangePortfolio(Portfolio):
|
|||||||
log.debug('updated portfolio with executed order')
|
log.debug('updated portfolio with executed order')
|
||||||
|
|
||||||
def remove_order(self, order):
|
def remove_order(self, order):
|
||||||
|
"""
|
||||||
|
Removing an open order.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
order: Order
|
||||||
|
|
||||||
|
"""
|
||||||
log.info('removing cancelled order {}'.format(order.id))
|
log.info('removing cancelled order {}'.format(order.id))
|
||||||
del self.open_orders[order.id]
|
del self.open_orders[order.id]
|
||||||
|
|
||||||
|
|||||||
@@ -2,12 +2,11 @@ import json
|
|||||||
import os
|
import os
|
||||||
import pickle
|
import pickle
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from catalyst.assets._assets import TradingPair
|
|
||||||
from six.moves.urllib import request
|
|
||||||
from datetime import date, datetime
|
from datetime import date, datetime
|
||||||
|
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
|
from catalyst.assets._assets import TradingPair
|
||||||
|
from six.moves.urllib import request
|
||||||
|
|
||||||
from catalyst.exchange.exchange_errors import ExchangeSymbolsNotFound, \
|
from catalyst.exchange.exchange_errors import ExchangeSymbolsNotFound, \
|
||||||
InvalidHistoryFrequencyError, InvalidHistoryFrequencyAlias
|
InvalidHistoryFrequencyError, InvalidHistoryFrequencyAlias
|
||||||
@@ -22,9 +21,15 @@ def get_exchange_folder(exchange_name, environ=None):
|
|||||||
"""
|
"""
|
||||||
The root path of an exchange folder.
|
The root path of an exchange folder.
|
||||||
|
|
||||||
:param exchange_name:
|
Parameters
|
||||||
:param environ:
|
----------
|
||||||
:return:
|
exchange_name: str
|
||||||
|
environ:
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
str
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if not environ:
|
if not environ:
|
||||||
environ = os.environ
|
environ = os.environ
|
||||||
@@ -40,9 +45,15 @@ def get_exchange_symbols_filename(exchange_name, environ=None):
|
|||||||
"""
|
"""
|
||||||
The absolute path of the exchange's symbol.json file.
|
The absolute path of the exchange's symbol.json file.
|
||||||
|
|
||||||
:param exchange_name:
|
Parameters
|
||||||
:param environ:
|
----------
|
||||||
:return:
|
exchange_name:
|
||||||
|
environ:
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
str
|
||||||
|
|
||||||
"""
|
"""
|
||||||
exchange_folder = get_exchange_folder(exchange_name, environ)
|
exchange_folder = get_exchange_folder(exchange_name, environ)
|
||||||
return os.path.join(exchange_folder, 'symbols.json')
|
return os.path.join(exchange_folder, 'symbols.json')
|
||||||
|
|||||||
Reference in New Issue
Block a user