mirror of
https://github.com/wassname/catalyst.git
synced 2026-06-29 15:25:57 +08:00
Refactoring to optimize multiple exchanges
This commit is contained in:
@@ -17,8 +17,8 @@ from logbook import Logger
|
||||
from catalyst.exchange.exchange import Exchange
|
||||
from catalyst.exchange.exchange_errors import (
|
||||
ExchangeRequestError,
|
||||
InvalidHistoryFrequencyError
|
||||
)
|
||||
InvalidHistoryFrequencyError,
|
||||
InvalidOrderType)
|
||||
from catalyst.finance.execution import (MarketOrder,
|
||||
LimitOrder,
|
||||
StopOrder,
|
||||
@@ -40,7 +40,7 @@ class Bitfinex(Exchange):
|
||||
def __init__(self, key, secret, base_currency, portfolio=None):
|
||||
self.url = BITFINEX_URL
|
||||
self.key = key
|
||||
self.secret = secret
|
||||
self.secret = secret.encode('UTF-8')
|
||||
self.name = 'bitfinex'
|
||||
self.assets = {}
|
||||
self.load_assets()
|
||||
@@ -359,89 +359,26 @@ class Bitfinex(Exchange):
|
||||
return ohlc_map[assets] \
|
||||
if isinstance(assets, TradingPair) else ohlc_map
|
||||
|
||||
def order(self, asset, amount, limit_price, stop_price, style):
|
||||
"""Place an order.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
asset : Asset
|
||||
The asset that this order is for.
|
||||
amount : int
|
||||
The amount of shares to order. If ``amount`` is positive, this is
|
||||
the number of shares to buy or cover. If ``amount`` is negative,
|
||||
this is the number of shares to sell or short.
|
||||
limit_price : float, optional
|
||||
The limit price for the order.
|
||||
stop_price : float, optional
|
||||
The stop price for the order.
|
||||
style : ExecutionStyle, optional
|
||||
The execution style for the order.
|
||||
|
||||
Returns
|
||||
-------
|
||||
order_id : str or None
|
||||
The unique identifier for this order, or None if no order was
|
||||
placed.
|
||||
|
||||
Notes
|
||||
-----
|
||||
The ``limit_price`` and ``stop_price`` arguments provide shorthands for
|
||||
passing common execution styles. Passing ``limit_price=N`` is
|
||||
equivalent to ``style=LimitOrder(N)``. Similarly, passing
|
||||
``stop_price=M`` is equivalent to ``style=StopOrder(M)``, and passing
|
||||
``limit_price=N`` and ``stop_price=M`` is equivalent to
|
||||
``style=StopLimitOrder(N, M)``. It is an error to pass both a ``style``
|
||||
and ``limit_price`` or ``stop_price``.
|
||||
|
||||
Bitfinex Order Types
|
||||
--------------------
|
||||
LIMIT, MARKET, STOP, TRAILING STOP,
|
||||
EXCHANGE MARKET, EXCHANGE LIMIT, EXCHANGE STOP,
|
||||
EXCHANGE TRAILING STOP, FOK, EXCHANGE FOK.
|
||||
|
||||
See Also
|
||||
--------
|
||||
:class:`catalyst.finance.execution.ExecutionStyle`
|
||||
:func:`catalyst.api.order_value`
|
||||
:func:`catalyst.api.order_percent`
|
||||
def create_order(self, asset, amount, is_buy, style):
|
||||
"""
|
||||
if amount == 0:
|
||||
log.warn('skipping order amount of 0')
|
||||
return None
|
||||
|
||||
base_currency = asset.symbol.split('_')[1]
|
||||
if base_currency.lower() != self.base_currency.lower():
|
||||
raise NotImplementedError(
|
||||
'Currency pairs must share their base with the exchange.'
|
||||
)
|
||||
|
||||
is_buy = (amount > 0)
|
||||
|
||||
if isinstance(style, MarketOrder):
|
||||
order_type = 'market'
|
||||
elif isinstance(style, LimitOrder):
|
||||
order_type = 'limit'
|
||||
price = limit_price
|
||||
elif isinstance(style, StopOrder):
|
||||
order_type = 'stop'
|
||||
price = stop_price
|
||||
elif isinstance(style, StopLimitOrder):
|
||||
log.warn('using limit order instead of stop/limit')
|
||||
# TODO: Not sure how to do this with the api. Investigate.
|
||||
order_type = 'limit'
|
||||
price = limit_price
|
||||
else:
|
||||
raise NotImplementedError('%s orders not available' % style)
|
||||
|
||||
log.debug(
|
||||
'ordering {amount} {symbol} for {price}'.format(
|
||||
amount=amount,
|
||||
symbol=asset.symbol,
|
||||
price=price
|
||||
)
|
||||
)
|
||||
Creating order on the exchange.
|
||||
|
||||
:param asset:
|
||||
:param amount:
|
||||
:param is_buy:
|
||||
:param style:
|
||||
:return:
|
||||
"""
|
||||
exchange_symbol = self.get_symbol(asset)
|
||||
if isinstance(style, LimitOrder) or isinstance(style, StopLimitOrder):
|
||||
price = style.get_limit_price(is_buy)
|
||||
order_type = 'limit'
|
||||
elif isinstance(style, StopOrder):
|
||||
price = style.get_stop_price(is_buy)
|
||||
order_type = 'stop'
|
||||
else:
|
||||
raise InvalidOrderType()
|
||||
|
||||
req = dict(
|
||||
symbol=exchange_symbol,
|
||||
amount=str(float(abs(amount))),
|
||||
@@ -479,9 +416,6 @@ class Bitfinex(Exchange):
|
||||
limit=style.get_limit_price(is_buy),
|
||||
id=order_id
|
||||
)
|
||||
# TODO: is this required?
|
||||
order.broker_order_id = order_id
|
||||
|
||||
self.portfolio.create_order(order)
|
||||
|
||||
return order_id
|
||||
|
||||
@@ -76,7 +76,7 @@ class Bittrex(Exchange):
|
||||
def update_portfolio(self):
|
||||
pass
|
||||
|
||||
def order(self):
|
||||
def create_order(self, asset, amount, is_buy, style):
|
||||
log.info('creating order')
|
||||
pass
|
||||
|
||||
|
||||
@@ -14,10 +14,15 @@ from catalyst.data.data_portal import BASE_FIELDS
|
||||
from catalyst.errors import (
|
||||
SymbolNotFound,
|
||||
)
|
||||
from catalyst.exchange.exchange_errors import InvalidOrderType
|
||||
from catalyst.finance.order import ORDER_STATUS
|
||||
from catalyst.finance.transaction import Transaction
|
||||
from catalyst.exchange.exchange_utils import get_exchange_symbols
|
||||
from catalyst.exchange.exchange_portfolio import ExchangePortfolio
|
||||
from catalyst.finance.execution import (MarketOrder,
|
||||
LimitOrder,
|
||||
StopOrder,
|
||||
StopLimitOrder)
|
||||
|
||||
log = Logger('Exchange')
|
||||
|
||||
@@ -380,7 +385,10 @@ class Exchange:
|
||||
return pd.concat(frames)
|
||||
|
||||
@abstractmethod
|
||||
def order(self, asset, amount, limit_price, stop_price, style):
|
||||
def create_order(self, asset, amount, is_buy, style):
|
||||
pass
|
||||
|
||||
def order(self, asset, amount, limit_price, stop_price, style=None):
|
||||
"""Place an order.
|
||||
|
||||
Parameters
|
||||
@@ -420,7 +428,38 @@ class Exchange:
|
||||
:func:`catalyst.api.order_value`
|
||||
:func:`catalyst.api.order_percent`
|
||||
"""
|
||||
pass
|
||||
if amount == 0:
|
||||
log.warn('skipping order amount of 0')
|
||||
return None
|
||||
|
||||
if asset.base_currency != self.base_currency.lower():
|
||||
raise NotImplementedError(
|
||||
'Currency pairs must share their base with the exchange.'
|
||||
)
|
||||
|
||||
is_buy = (amount > 0)
|
||||
|
||||
if limit_price is not None and stop_price is not None:
|
||||
style = StopLimitOrder(limit_price, stop_price,
|
||||
exchange=self.name)
|
||||
elif limit_price is not None:
|
||||
style = LimitOrder(limit_price, exchange=self.name)
|
||||
elif stop_price is not None:
|
||||
style = StopOrder(stop_price, exchange=self.name)
|
||||
elif style is None:
|
||||
raise InvalidOrderType()
|
||||
|
||||
display_price = limit_price if limit_price is not None else stop_price
|
||||
log.debug(
|
||||
'issuing {side} order of {amount} {symbol} for {type}: {price}'.format(
|
||||
side='buy' if is_buy else 'sell',
|
||||
amount=amount,
|
||||
symbol=asset.symbol,
|
||||
type=style.__class__.__name__,
|
||||
price='{}{}'.format(display_price, asset.base_currency)
|
||||
)
|
||||
)
|
||||
return self.create_order(asset, amount, is_buy, style)
|
||||
|
||||
@abstractmethod
|
||||
def get_open_orders(self, asset):
|
||||
|
||||
@@ -67,3 +67,9 @@ class InvalidSymbolError(ZiplineError):
|
||||
'[Market Currency]_[Base Currency]. For example: eth_usd, btc_usd, '
|
||||
'neo_eth, ubq_btc. Error details: {error}'
|
||||
).strip()
|
||||
|
||||
|
||||
class InvalidOrderType(ZiplineError):
|
||||
msg = (
|
||||
'Order type not found.'
|
||||
).strip()
|
||||
|
||||
@@ -502,7 +502,7 @@ def run_algorithm(initialize,
|
||||
if exchange_name == 'bitfinex':
|
||||
exchange = Bitfinex(
|
||||
key=exchange_auth['key'],
|
||||
secret=exchange_auth['secret'].encode('UTF-8'),
|
||||
secret=exchange_auth['secret'],
|
||||
base_currency=base_currency,
|
||||
portfolio=portfolio
|
||||
)
|
||||
|
||||
@@ -24,6 +24,15 @@ class BitfinexTestCase(BaseExchangeTestCase):
|
||||
|
||||
def test_order(self):
|
||||
log.info('creating order')
|
||||
asset = self.exchange.get_asset('eth_usd')
|
||||
order_id = self.exchange.order(
|
||||
asset=asset,
|
||||
style=LimitOrder(limit_price=200),
|
||||
limit_price=200,
|
||||
amount=0.5,
|
||||
stop_price=None
|
||||
)
|
||||
log.info('order created {}'.format(order_id))
|
||||
pass
|
||||
|
||||
def test_open_orders(self):
|
||||
|
||||
@@ -24,6 +24,15 @@ class BittrexTestCase(BaseExchangeTestCase):
|
||||
|
||||
def test_order(self):
|
||||
log.info('creating order')
|
||||
asset = self.exchange.get_asset('neo_eth')
|
||||
order_id = self.exchange.order(
|
||||
asset=asset,
|
||||
style=LimitOrder(limit_price=200),
|
||||
limit_price=200,
|
||||
amount=0.5,
|
||||
stop_price=None
|
||||
)
|
||||
log.info('order created {}'.format(order_id))
|
||||
pass
|
||||
|
||||
def test_open_orders(self):
|
||||
|
||||
Reference in New Issue
Block a user