Extended Asset to create TradingPair allowing us to store leverage value

This commit is contained in:
fredfortier
2017-08-28 10:25:46 -04:00
parent c01f2a39a4
commit cf54806843
6 changed files with 145 additions and 46 deletions
+125 -23
View File
@@ -20,15 +20,17 @@ Cythonized Asset object.
cimport cython
from cpython.number cimport PyNumber_Index
from cpython.object cimport (
Py_EQ,
Py_NE,
Py_GE,
Py_LE,
Py_GT,
Py_LT,
Py_EQ,
Py_NE,
Py_GE,
Py_LE,
Py_GT,
Py_LT,
)
from cpython cimport bool
import pandas as pd
from datetime import timedelta
import numpy as np
from numpy cimport int64_t
import warnings
@@ -36,15 +38,12 @@ cimport numpy as np
from catalyst.utils.calendars import get_calendar
# IMPORTANT NOTE: You must change this template if you change
# Asset.__reduce__, or else we'll attempt to unpickle an old version of this
# class
CACHE_FILE_TEMPLATE = '/tmp/.%s-%s.v7.cache'
cdef class Asset:
cdef readonly int sid
# Cached hash of self.sid
cdef int sid_hash
@@ -73,8 +72,8 @@ cdef class Asset:
})
def __init__(self,
int sid, # sid is required
object exchange, # exchange is required
int sid, # sid is required
object exchange, # exchange is required
object symbol="",
object asset_name="",
object start_date=None,
@@ -230,9 +229,7 @@ cdef class Asset:
calendar = get_calendar(self.exchange)
return calendar.is_open_on_minute(dt_minute)
cdef class Equity(Asset):
def __repr__(self):
attrs = ('symbol', 'asset_name', 'exchange',
'start_date', 'end_date', 'first_traded', 'auto_close_date',
@@ -250,8 +247,8 @@ cdef class Equity(Asset):
"""
def __get__(self):
warnings.warn("The security_start_date property will soon be "
"retired. Please use the start_date property instead.",
DeprecationWarning)
"retired. Please use the start_date property instead.",
DeprecationWarning)
return self.start_date
property security_end_date:
@@ -261,8 +258,8 @@ cdef class Equity(Asset):
"""
def __get__(self):
warnings.warn("The security_end_date property will soon be "
"retired. Please use the end_date property instead.",
DeprecationWarning)
"retired. Please use the end_date property instead.",
DeprecationWarning)
return self.end_date
property security_name:
@@ -272,13 +269,11 @@ cdef class Equity(Asset):
"""
def __get__(self):
warnings.warn("The security_name property will soon be "
"retired. Please use the asset_name property instead.",
DeprecationWarning)
"retired. Please use the asset_name property instead.",
DeprecationWarning)
return self.asset_name
cdef class Future(Asset):
cdef readonly object root_symbol
cdef readonly object notice_date
cdef readonly object expiration_date
@@ -303,8 +298,8 @@ cdef class Future(Asset):
})
def __init__(self,
int sid, # sid is required
object exchange, # exchange is required
int sid, # sid is required
object exchange, # exchange is required
object symbol="",
object root_symbol="",
object asset_name="",
@@ -388,6 +383,113 @@ cdef class Future(Asset):
super_dict['multiplier'] = self.multiplier
return super_dict
cdef class TradingPair(Asset):
cdef readonly float leverage
_kwargnames = frozenset({
'sid',
'symbol',
'asset_name',
'start_date',
'end_date',
'first_traded',
'auto_close_date',
'exchange',
'exchange_full',
'leverage',
})
def __init__(self,
object symbol,
object exchange,
object start_date=None,
object asset_name=None,
int sid=0,
float leverage=1.0,
object end_date=None,
object first_traded=None,
object auto_close_date=None,
object exchange_full=None):
"""
Replicates the Asset constructor with some built-in conventions
and a new 'leverage' attribute.
Symbol
------
Catalyst defines its own set of "universal" symbols to reference
trading pairs across exchanges. This is required because exchanges
are not adhering to a universal symbolism. For example, Bitfinex
uses the BTC symbol for Bitcon while Kraken uses XBT. In addition,
pairs are sometimes presented differently. For example, Bitfinex
puts the market currency before the base currency without a
separator, Bittrex puts the base currency first and uses a dash
seperator.
Here is the Catalyst convention: [Market Currency]_[Base Currency]
For example: btc_usd, eth_btc, neo_eth, ltc_eur.
The symbol for each currency (e.g. btc, eth, ltc) is generally
aligned with the Bittrex exchange.
Sid
---
The sid of each asset is calculated based on a numeric hash of the
universal symbol. This simple approach avoids maintaining a mapping
of sids.
Leverage
--------
In contrast with equities, crypto exchanges generally assign
leverage values to specific trading pairs. Pairs with the
highest volume and market cap generally benefit from high leverage.
New currencies from ICO generally cannot be leveraged.
The leverage value is either None or and integer.
Leverage allows you to open a larger position with a smaller amount
of funds. For example, if you open a $5,000 position in BTC/USD
with 5:1 leverage, only one-fifth of this amount, or $1000, will be
tied to the position from your balance. Your remaining balance will
be available for opening more positions. If you open this same
position with 2:1 leverage, $2,500 of your balance will be tied to
the position. If you open with 1:1 leverage, $5,000 of your balance
will be tied to the position.
:param symbol:
:param exchange:
:param start_date:
:param asset_name:
:param sid:
:param leverage:
:param end_date:
:param first_traded:
:param auto_close_date:
:param exchange_full:
"""
asset_name = ' / '.join(symbol.split('_')).upper() \
if asset_name is None else asset_name
start_date = pd.Timestamp.utcnow() \
if start_date is None else start_date
end_date = start_date + timedelta(days=1) \
if end_date is None else end_date
sid = abs(hash(symbol)) % (10 ** 4) \
if sid == 0 else sid
super().__init__(
sid,
exchange,
symbol=symbol,
asset_name=asset_name,
start_date=start_date,
end_date=end_date,
first_traded=first_traded,
auto_close_date=auto_close_date,
exchange_full=exchange_full,
)
self.leverage = leverage
def make_asset_array(int size, Asset asset):
cdef np.ndarray out = np.empty([size], dtype=object)
+1 -1
View File
@@ -81,7 +81,7 @@ class AssetFinderExchange(object):
there are multiple candidates for the given ``symbol`` on the
``as_of_date``.
"""
log.info('looking up symbol: {}'.format(symbol))
log.debug('looking up symbol: {}'.format(symbol))
if symbol in self._asset_cache:
return self._asset_cache[symbol]
+3 -3
View File
@@ -10,7 +10,7 @@ import pandas as pd
import pytz
import requests
import six
from catalyst.assets._assets import Asset
from catalyst.assets._assets import TradingPair
from logbook import Logger
# from websocket import create_connection
@@ -300,7 +300,7 @@ class Bitfinex(Exchange):
)
# Making sure that assets are iterable
asset_list = [assets] if isinstance(assets, Asset) else assets
asset_list = [assets] if isinstance(assets, TradingPair) else assets
ohlc_map = dict()
for asset in asset_list:
symbol = self._get_v2_symbol(asset)
@@ -357,7 +357,7 @@ class Bitfinex(Exchange):
ohlc_map[asset] = ohlc
return ohlc_map[assets] \
if isinstance(assets, Asset) else ohlc_map
if isinstance(assets, TradingPair) else ohlc_map
def order(self, asset, amount, limit_price, stop_price, style):
"""Place an order.
+3 -3
View File
@@ -7,7 +7,7 @@ import pandas as pd
from catalyst.exchange.exchange import Exchange
from catalyst.exchange.bittrex.bittrex_api import Bittrex_api
from catalyst.assets._assets import Asset
from catalyst.assets._assets import TradingPair
log = Logger('Bittrex')
@@ -123,7 +123,7 @@ class Bittrex(Exchange):
)
# Making sure that assets are iterable
asset_list = [assets] if isinstance(assets, Asset) else assets
asset_list = [assets] if isinstance(assets, TradingPair) else assets
ohlc_map = dict()
for asset in asset_list:
url = '{url}/pub/market/GetTicks?marketName={symbol}' \
@@ -169,7 +169,7 @@ class Bittrex(Exchange):
ohlc_map[asset] = ohlc_bars
return ohlc_map[assets] \
if isinstance(assets, Asset) else ohlc_map
if isinstance(assets, TradingPair) else ohlc_map
def tickers(self):
log.info('retrieving tickers')
+5 -11
View File
@@ -7,7 +7,7 @@ from datetime import timedelta
import numpy as np
import pandas as pd
from catalyst.assets._assets import Asset
from catalyst.assets._assets import TradingPair
from logbook import Logger
from catalyst.data.data_portal import BASE_FIELDS
@@ -138,19 +138,13 @@ class Exchange:
symbol_map = self.fetch_symbol_map()
for exchange_symbol in symbol_map:
asset = symbol_map[exchange_symbol]
symbol = asset['symbol']
asset_name = ' / '.join(symbol.split('_')).upper()
asset_obj = Asset(
symbol=symbol,
asset_name=asset_name,
sid=abs(hash(symbol)) % (10 ** 4),
trading_pair = TradingPair(
symbol=asset['symbol'],
exchange=self.name,
start_date=pd.to_datetime(asset['start_date'], utc=True),
end_date=pd.Timestamp.utcnow() + timedelta(minutes=300000),
start_date=pd.to_datetime(asset['start_date']),
)
self.assets[exchange_symbol] = asset_obj
self.assets[exchange_symbol] = trading_pair
def check_open_orders(self):
"""
+8 -5
View File
@@ -38,6 +38,7 @@ class LazyBuildExtCommandClass(dict):
Lazy command class that defers operations requiring Cython and numpy until
they've actually been downloaded and installed by setup_requires.
"""
def __contains__(self, key):
return (
key == 'build_ext'
@@ -62,6 +63,7 @@ class LazyBuildExtCommandClass(dict):
Custom build_ext command that lazily adds numpy's include_dir to
extensions.
"""
def build_extensions(self):
"""
Lazily append numpy's include directory to Extension includes.
@@ -75,6 +77,7 @@ class LazyBuildExtCommandClass(dict):
ext.include_dirs.append(numpy_incl)
super(build_ext, self).build_extensions()
return build_ext
@@ -100,7 +103,8 @@ ext_modules = [
window_specialization('label'),
Extension('catalyst.lib.rank', ['catalyst/lib/rank.pyx']),
Extension('catalyst.data._equities', ['catalyst/data/_equities.pyx']),
Extension('catalyst.data._adjustments', ['catalyst/data/_adjustments.pyx']),
Extension('catalyst.data._adjustments',
['catalyst/data/_adjustments.pyx']),
Extension('catalyst._protocol', ['catalyst/_protocol.pyx']),
Extension('catalyst.gens.sim_engine', ['catalyst/gens/sim_engine.pyx']),
Extension(
@@ -117,7 +121,6 @@ ext_modules = [
),
]
STR_TO_CMP = {
'<': lt,
'<=': le,
@@ -264,6 +267,7 @@ def setup_requirements(requirements_path, module_names, strict_bounds,
)
return module_lines
conda_build = os.path.basename(sys.argv[0]) in ('conda-build', # unix
'conda-build-script.py') # win
@@ -295,7 +299,7 @@ setup(
ext_modules=ext_modules,
include_package_data=True,
package_data={root.replace(os.sep, '.'):
['*.pyi', '*.pyx', '*.pxi', '*.pxd']
['*.pyi', '*.pyx', '*.pxi', '*.pxd']
for root, dirnames, filenames in os.walk('catalyst')
if '__pycache__' not in root},
license='Apache 2.0',
@@ -314,7 +318,6 @@ setup(
'Topic :: System :: Distributed Computing',
],
install_requires=install_requires(conda_format=conda_build),
extras_require=extras_requires(conda_format=conda_build,
install_requires=['six']),
extras_require=extras_requires(conda_format=conda_build),
**conditional_arguments
)