Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
lenak25 committed Jun 21, 2018
2 parents 284758e + 4887e8d commit e52a117
Show file tree
Hide file tree
Showing 15 changed files with 158 additions and 82 deletions.
10 changes: 5 additions & 5 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#
# To access Jupyter when running docker locally (you may need to add NAT rules):
#
# https://127.0.0.1
# https://127.0.0.1:8888 <- Please note HTTPS, not HTTP
#
# Default password is 'jupyter'. To provide another, see:
# http://jupyter-notebook.readthedocs.org/en/latest/public_server.html#preparing-a-hashed-password
Expand All @@ -21,7 +21,7 @@
#
# docker exec -it catalyst catalyst run -f /projects/my_algo.py --start 2015-1-1 --end 2016-1-1 /projects/result.pickle
#
FROM python:3.5
FROM python:3.6

#
# set up environment
Expand Down Expand Up @@ -54,9 +54,9 @@ RUN mkdir ${PROJECT_DIR} \

WORKDIR /ta-lib

RUN pip install 'numpy>=1.11.1,<2.0.0' \
&& pip install 'scipy>=0.17.1,<1.0.0' \
&& pip install 'pandas>=0.18.1,<1.0.0' \
RUN pip install 'numpy==1.14.0' \
&& pip install 'scipy==1.0.0' \
&& pip install 'pandas==0.19.2' \
&& ./configure --prefix=/usr \
&& make \
&& make install \
Expand Down
3 changes: 3 additions & 0 deletions catalyst/_protocol.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,10 @@ cdef class BarData:
the current trade bar. If there is no current trade bar, NaN is
returned.
In live mode, "volume", "close" and "price" are the only available fields.
In live mode, "volume" returns the last 24 hour trading volume.
"""
multiple_assets = _is_iterable(assets)
multiple_fields = _is_iterable(fields)
Expand Down
4 changes: 3 additions & 1 deletion catalyst/algorithm.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
StopLimitOrder,
StopOrder,
)
from catalyst.finance.order import Order
from catalyst.finance.performance import PerformanceTracker
from catalyst.finance.asset_restrictions import Restrictions
from catalyst.finance.cancel_policy import NeverCancel, CancelPolicy
Expand Down Expand Up @@ -2104,7 +2105,8 @@ def cancel_order(self, order_param):
The order_id or order object to cancel.
"""
order_id = order_param
if isinstance(order_param, catalyst.protocol.Order):
if isinstance(order_param, catalyst.protocol.Order) or \
isinstance(order_param, Order):
order_id = order_param.id

self.blotter.cancel(order_id)
Expand Down
12 changes: 10 additions & 2 deletions catalyst/api.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,17 @@ def batch_market_order(share_counts):
"""


def cancel_order(order_param):
def cancel_order(order_param, symbol=None, params={}):
"""Cancel an open order.
Parameters
----------
order_param : str or Order
The order_id or order object to cancel.
symbol: str
The tradingPair symbol
params: dict, optional
Extra parameters to pass to the exchange
"""


Expand Down Expand Up @@ -209,14 +213,18 @@ def get_environment(field='platform'):
"""


def get_order(order_id):
def get_order(order_id, asset_or_symbol=None, return_price=False):
"""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.
asset_or_symbol: Asset or str
The asset or the tradingPair symbol of the order.
return_price: bool
get the trading price in addition to the order
Returns
-------
Expand Down
8 changes: 3 additions & 5 deletions catalyst/examples/arbitrage_with_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
from catalyst.api import (
record,
order,
symbol,
get_open_orders
symbol
)
from catalyst.exchange.utils.stats_utils import get_pretty_stats
from catalyst.utils.run_algo import run_algorithm
Expand Down Expand Up @@ -200,12 +199,11 @@ def handle_data(context, data):
for exchange in context.trading_pairs:
asset = context.trading_pairs[exchange]

orders = get_open_orders(asset)
if orders:
if asset in context.blotter.open_orders:
log.info(
'found {order_count} open orders on {exchange_name} '
'skipping bar until all open orders execute'.format(
order_count=len(orders),
order_count=len(context.blotter.open_orders(asset)),
exchange_name=exchange.name
)
)
Expand Down
1 change: 0 additions & 1 deletion catalyst/examples/talib_simple.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ def initialize(context):
context.ORDER_SIZE = 10
context.SLIPPAGE_ALLOWED = 0.05

context.swallow_errors = True
context.errors = []

# Bars to look at per iteration should be bigger than SMA_SLOW
Expand Down
54 changes: 44 additions & 10 deletions catalyst/exchange/ccxt/ccxt_exchange.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
get_periods_range
from catalyst.finance.order import Order, ORDER_STATUS
from catalyst.finance.transaction import Transaction
from redo import retry

log = Logger('CCXT', level=LOG_LEVEL)

Expand Down Expand Up @@ -82,6 +83,12 @@ def __init__(self, exchange_name, key,
self.request_cpt = dict()
self._common_symbols = dict()

# Operations with retry features
self.attempts = dict(
missing_order_attempts=5,
retry_sleeptime=5,
)

self.bundle = ExchangeBundle(self.name)
self.markets = None
self._is_init = False
Expand Down Expand Up @@ -722,7 +729,12 @@ def _create_order(self, order_status):

limit_price = price if order_type == 'limit' else None

executed_price = order_status['cost'] / order_status['amount']
if 'price' in order_status:
executed_price = order_status['price']
elif 'cost' in order_status and "amount" in order_status:
executed_price = order_status['cost'] / order_status['amount']
else:
executed_price = None
commission = order_status['fee']
date = from_ms_timestamp(order_status['timestamp'])

Expand Down Expand Up @@ -837,8 +849,9 @@ def _handle_request_timeout(self, dt_before, asset, amount, is_buy, style,
:param adj_amount: int
:return: missing_order: Order/ None
"""
symbol = asset.asset_name.replace(' ', '')
missing_order_id, missing_order = self._fetch_missing_order(
dt_before=dt_before, symbol=asset.asset_name)
dt_before=dt_before, symbol=symbol)

if missing_order_id:
final_amount = adj_amount if amount > 0 else -adj_amount
Expand Down Expand Up @@ -908,9 +921,15 @@ def create_order(self, asset, amount, is_buy, style):
'an order on {} / {}\n Checking if an order was filled '
'during the timeout'.format(self.name, symbol)
)

missing_order = self._handle_request_timeout(
before_order_dt, asset, amount, is_buy, style, adj_amount
missing_order = retry(
action=self._handle_request_timeout,
attempts=self.attempts['missing_order_attempts'],
sleeptime=self.attempts['retry_sleeptime'],
retry_exceptions=(RequestTimeout, ExchangeError),
cleanup=lambda: log.warn('Checking missing order again..'),
args=(
before_order_dt, asset, amount, is_buy, style, adj_amount
)
)
if missing_order is None:
# no order was found
Expand All @@ -920,6 +939,7 @@ def create_order(self, asset, amount, is_buy, style):
'We encourage you to report any issue on GitHub: '
'https://github.com/enigmampc/catalyst/issues'
)
# In order to try ordering again
raise ExchangeRequestError(error=e)
else:
return missing_order
Expand Down Expand Up @@ -999,11 +1019,6 @@ def _check_low_balance(self, currency, balances, amount):
return super(CCXT, self)._check_low_balance(updated_currency, balances,
amount)

def _check_position_balance(self, currency, balances, amount):
updated_currency = self._check_common_symbols(currency)
return super(CCXT, self)._check_position_balance(updated_currency,
balances, amount)

def _process_order_fallback(self, order):
"""
Fallback method for exchanges which do not play nice with
Expand Down Expand Up @@ -1128,6 +1143,25 @@ def process_order(self, order):
return transactions

def get_order(self, order_id, asset_or_symbol=None, return_price=False):
"""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.
asset_or_symbol: Asset or str
The asset or the tradingPair symbol of the order.
return_price: bool
get the trading price in addition to the order
Returns
-------
order : Order
The order object.
execution_price: float
The execution price per unit of the order if return_price is True
"""
if asset_or_symbol is None:
log.debug(
'order not found in memory, the request might fail '
Expand Down
30 changes: 6 additions & 24 deletions catalyst/exchange/exchange.py
Original file line number Diff line number Diff line change
Expand Up @@ -679,24 +679,6 @@ def get_history_window_with_bundle(self,
return df

def _check_low_balance(self, currency, balances, amount):
"""
In order to avoid spending money that the user doesn't own,
we are comparing to the balance on the account.
:param currency: str
:param balances: dict
:param amount: float
:return: free: float,
bool
"""
free = balances[currency]['free'] if currency in balances else 0.0

if free < amount:
return free, True

else:
return free, False

def _check_position_balance(self, currency, balances, amount):
"""
In order to avoid spending money that the user doesn't own,
we are comparing to the balance on the account.
Expand Down Expand Up @@ -732,17 +714,17 @@ def sync_positions(self, positions, cash=None,
Check balances amounts against the exchange.
"""
free_cash = 0.0
total_cash = 0.0
if check_balances:
log.debug('fetching {} balances'.format(self.name))
balances = self.get_balances()
log.debug(
'got free balances for {} currencies'.format(
'got balances for {} currencies'.format(
len(balances)
)
)
if cash is not None:
free_cash, is_lower = self._check_low_balance(
total_cash, is_lower = self._check_low_balance(
currency=self.quote_currency,
balances=balances,
amount=cash,
Expand All @@ -751,7 +733,7 @@ def sync_positions(self, positions, cash=None,
raise NotEnoughCashError(
currency=self.quote_currency,
exchange=self.name,
free=free_cash,
total=total_cash,
cash=cash,
)

Expand Down Expand Up @@ -782,7 +764,7 @@ def sync_positions(self, positions, cash=None,
position.last_sale_date = ticker['last_traded']

if check_balances:
total, is_lower = self._check_position_balance(
total, is_lower = self._check_low_balance(
currency=asset.base_currency,
balances=balances,
amount=position.amount,
Expand All @@ -800,7 +782,7 @@ def sync_positions(self, positions, cash=None,
positions_value += \
position.amount * position.last_sale_price

return free_cash, positions_value
return total_cash, positions_value

def order(self, asset, amount, style):
"""Place an order.
Expand Down
Loading

0 comments on commit e52a117

Please sign in to comment.