mirror of
https://github.com/wassname/catalyst.git
synced 2026-07-17 11:25:55 +08:00
Merge branch 'fractional-coins' into develop
This commit is contained in:
+7
-10
@@ -125,6 +125,7 @@ from catalyst.utils.factory import create_simulation_parameters
|
||||
from catalyst.utils.math_utils import (
|
||||
tolerant_equals,
|
||||
round_if_near_integer,
|
||||
round_nearest
|
||||
)
|
||||
from catalyst.utils.pandas_utils import clear_dataframe_indexer_caches
|
||||
from catalyst.utils.preprocess import preprocess
|
||||
@@ -1488,7 +1489,7 @@ class TradingAlgorithm(object):
|
||||
|
||||
def _calculate_order(self, asset, amount,
|
||||
limit_price=None, stop_price=None, style=None):
|
||||
amount = self.round_order(amount)
|
||||
amount = self.round_order(amount, asset)
|
||||
|
||||
# Raises a ZiplineError if invalid parameters are detected.
|
||||
self.validate_order_params(asset,
|
||||
@@ -1505,16 +1506,13 @@ class TradingAlgorithm(object):
|
||||
return amount, style
|
||||
|
||||
@staticmethod
|
||||
def round_order(amount):
|
||||
def round_order(amount, asset):
|
||||
"""
|
||||
Convert number of shares to an integer.
|
||||
|
||||
By default, truncates to the integer share count that's either within
|
||||
.0001 of amount or closer to zero.
|
||||
|
||||
E.g. 3.9999 -> 4.0; 5.5 -> 5.0; -5.5 -> -5.0
|
||||
Converts the number of shares to the smallest tradable lot size for
|
||||
the asset being ordered.
|
||||
|
||||
"""
|
||||
return int(round_if_near_integer(amount))
|
||||
return round_nearest(amount, asset.min_trade_size)
|
||||
|
||||
def validate_order_params(self,
|
||||
asset,
|
||||
@@ -1550,7 +1548,6 @@ class TradingAlgorithm(object):
|
||||
self.updated_portfolio(),
|
||||
self.get_datetime(),
|
||||
self.trading_client.current_data)
|
||||
|
||||
@staticmethod
|
||||
def __convert_order_params_for_blotter(limit_price, stop_price, style):
|
||||
"""
|
||||
|
||||
@@ -59,6 +59,7 @@ cdef class Asset:
|
||||
|
||||
cdef readonly object exchange
|
||||
cdef readonly object exchange_full
|
||||
cdef readonly object min_trade_size
|
||||
|
||||
_kwargnames = frozenset({
|
||||
'sid',
|
||||
@@ -70,6 +71,7 @@ cdef class Asset:
|
||||
'auto_close_date',
|
||||
'exchange',
|
||||
'exchange_full',
|
||||
'min_trade_size',
|
||||
})
|
||||
|
||||
def __init__(self,
|
||||
@@ -81,7 +83,8 @@ cdef class Asset:
|
||||
object end_date=None,
|
||||
object first_traded=None,
|
||||
object auto_close_date=None,
|
||||
object exchange_full=None):
|
||||
object exchange_full=None,
|
||||
object min_trade_size=None):
|
||||
|
||||
self.sid = sid
|
||||
self.sid_hash = hash(sid)
|
||||
@@ -94,6 +97,7 @@ cdef class Asset:
|
||||
self.end_date = end_date
|
||||
self.first_traded = first_traded
|
||||
self.auto_close_date = auto_close_date
|
||||
self.min_trade_size = min_trade_size
|
||||
|
||||
def __int__(self):
|
||||
return self.sid
|
||||
@@ -148,7 +152,8 @@ cdef class Asset:
|
||||
|
||||
def __repr__(self):
|
||||
attrs = ('symbol', 'asset_name', 'exchange',
|
||||
'start_date', 'end_date', 'first_traded', 'auto_close_date')
|
||||
'start_date', 'end_date', 'first_traded', 'auto_close_date',
|
||||
'min_trade_size')
|
||||
tuples = ((attr, repr(getattr(self, attr, None)))
|
||||
for attr in attrs)
|
||||
strings = ('%s=%s' % (t[0], t[1]) for t in tuples)
|
||||
@@ -170,7 +175,8 @@ cdef class Asset:
|
||||
self.end_date,
|
||||
self.first_traded,
|
||||
self.auto_close_date,
|
||||
self.exchange_full))
|
||||
self.exchange_full,
|
||||
self.min_trade_size))
|
||||
|
||||
cpdef to_dict(self):
|
||||
"""
|
||||
@@ -186,6 +192,7 @@ cdef class Asset:
|
||||
'auto_close_date': self.auto_close_date,
|
||||
'exchange': self.exchange,
|
||||
'exchange_full': self.exchange_full,
|
||||
'min_trade_size': self.min_trade_size
|
||||
}
|
||||
|
||||
@classmethod
|
||||
@@ -234,7 +241,7 @@ cdef class Equity(Asset):
|
||||
def __repr__(self):
|
||||
attrs = ('symbol', 'asset_name', 'exchange',
|
||||
'start_date', 'end_date', 'first_traded', 'auto_close_date',
|
||||
'exchange_full')
|
||||
'exchange_full', 'min_trade_size')
|
||||
tuples = ((attr, repr(getattr(self, attr, None)))
|
||||
for attr in attrs)
|
||||
strings = ('%s=%s' % (t[0], t[1]) for t in tuples)
|
||||
|
||||
@@ -39,7 +39,8 @@ equities = sa.Table(
|
||||
sa.Column('first_traded', sa.Integer),
|
||||
sa.Column('auto_close_date', sa.Integer),
|
||||
sa.Column('exchange', sa.Text),
|
||||
sa.Column('exchange_full', sa.Text)
|
||||
sa.Column('exchange_full', sa.Text),
|
||||
sa.Column('min_trade_size', sa.Float)
|
||||
)
|
||||
|
||||
equity_symbol_mappings = sa.Table(
|
||||
|
||||
@@ -73,6 +73,7 @@ _equities_defaults = {
|
||||
'exchange': None,
|
||||
# optional, something like "New York Stock Exchange"
|
||||
'exchange_full': None,
|
||||
'min_trade_size': 1
|
||||
}
|
||||
|
||||
# Default values for the futures DataFrame
|
||||
@@ -390,6 +391,8 @@ class AssetDBWriter(object):
|
||||
The date on which to close any positions in this asset.
|
||||
exchange : str
|
||||
The exchange where this asset is traded.
|
||||
min_trade_size: float, optional
|
||||
The minimum denomination this asset can be traded.
|
||||
|
||||
The index of this dataframe should contain the sids.
|
||||
futures : pd.DataFrame, optional
|
||||
|
||||
@@ -24,6 +24,7 @@ class BasePricingBundle(BaseBundle):
|
||||
('start_date', 'datetime64[ns]'),
|
||||
('end_date', 'datetime64[ns]'),
|
||||
('ac_date', 'datetime64[ns]'),
|
||||
('min_trade_size', 'float'),
|
||||
]
|
||||
|
||||
@lazyval
|
||||
|
||||
@@ -77,12 +77,14 @@ class PoloniexBundle(BaseCryptoPricingBundle):
|
||||
start_date = sym_data.index[0]
|
||||
end_date = sym_data.index[-1]
|
||||
ac_date = end_date + pd.Timedelta(days=1)
|
||||
min_trade_size = 0.00000001
|
||||
|
||||
return (
|
||||
sym_md.symbol,
|
||||
start_date,
|
||||
end_date,
|
||||
ac_date,
|
||||
min_trade_size,
|
||||
)
|
||||
|
||||
def fetch_raw_symbol_frame(self,
|
||||
|
||||
@@ -41,6 +41,7 @@ DEFAULT_EQUITY_VOLUME_SLIPPAGE_BAR_LIMIT = 0.025
|
||||
DEFAULT_FUTURE_VOLUME_SLIPPAGE_BAR_LIMIT = 0.05
|
||||
|
||||
|
||||
|
||||
class LiquidityExceeded(Exception):
|
||||
pass
|
||||
|
||||
@@ -205,20 +206,22 @@ class VolumeShareSlippage(SlippageModel):
|
||||
def process_order(self, data, order):
|
||||
volume = data.current(order.asset, "volume")
|
||||
|
||||
min_trade_size = order.asset.min_trade_size
|
||||
|
||||
max_volume = self.volume_limit * volume
|
||||
|
||||
# price impact accounts for the total volume of transactions
|
||||
# created against the current minute bar
|
||||
remaining_volume = max_volume - self.volume_for_bar
|
||||
if remaining_volume < 1:
|
||||
if remaining_volume < min_trade_size:
|
||||
# we can't fill any more transactions
|
||||
raise LiquidityExceeded()
|
||||
|
||||
# the current order amount will be the min of the
|
||||
# volume available in the bar or the open amount.
|
||||
cur_volume = int(min(remaining_volume, abs(order.open_amount)))
|
||||
cur_volume = min(remaining_volume, abs(order.open_amount))
|
||||
|
||||
if cur_volume < 1:
|
||||
if cur_volume < min_trade_size:
|
||||
return None, None
|
||||
|
||||
# tally the current amount into our total amount ordered.
|
||||
|
||||
@@ -65,14 +65,10 @@ def create_transaction(order, dt, price, amount):
|
||||
# floor the amount to protect against non-whole number orders
|
||||
# TODO: Investigate whether we can add a robust check in blotter
|
||||
# and/or tradesimulation, as well.
|
||||
amount_magnitude = int(abs(amount))
|
||||
|
||||
if amount_magnitude < 1:
|
||||
raise Exception("Transaction magnitude must be at least 1.")
|
||||
|
||||
transaction = Transaction(
|
||||
asset=order.asset,
|
||||
amount=int(amount),
|
||||
amount=amount,
|
||||
dt=dt,
|
||||
price=price,
|
||||
order_id=order.id
|
||||
|
||||
@@ -17,6 +17,8 @@ import math
|
||||
|
||||
from numpy import isnan
|
||||
|
||||
def round_nearest(x, a):
|
||||
return round(round(x / a) * a, -int(math.floor(math.log10(a))))
|
||||
|
||||
def tolerant_equals(a, b, atol=10e-7, rtol=10e-7, equal_nan=False):
|
||||
"""Check if a and b are equal with some tolerance.
|
||||
|
||||
Reference in New Issue
Block a user