diff --git a/catalyst/exchange/ccxt/ccxt_exchange.py b/catalyst/exchange/ccxt/ccxt_exchange.py index b17eccc1..c6bed5b4 100644 --- a/catalyst/exchange/ccxt/ccxt_exchange.py +++ b/catalyst/exchange/ccxt/ccxt_exchange.py @@ -1016,19 +1016,27 @@ class CCXT(Exchange): return result def get_trades(self, asset, my_trades=True, start_dt=None, limit=100): - if not my_trades: - raise NotImplemented( - 'get_trades only supports "my trades"' - ) - # TODO: is it possible to sort this? Limit is useless otherwise. ccxt_symbol = self.get_symbol(asset) + if start_dt: + delta = start_dt - get_epoch() + since = int(delta.total_seconds()) * 1000 + else: + since = None + try: - trades = self.api.fetch_my_trades( - symbol=ccxt_symbol, - since=start_dt, - limit=limit, - ) + if my_trades: + trades = self.api.fetch_my_trades( + symbol=ccxt_symbol, + since=since, + limit=limit, + ) + else: + trades = self.api.fetch_trades( + symbol=ccxt_symbol, + since=since, + limit=limit, + ) except (ExchangeError, NetworkError) as e: log.warn( 'unable to fetch trades {} / {}: {}'.format( diff --git a/catalyst/exchange/utils/exchange_utils.py b/catalyst/exchange/utils/exchange_utils.py index 45d1664a..502bed01 100644 --- a/catalyst/exchange/utils/exchange_utils.py +++ b/catalyst/exchange/utils/exchange_utils.py @@ -1,18 +1,16 @@ import hashlib -import json import os -import pickle import shutil -from datetime import date, datetime +import json import pandas as pd +import pickle from catalyst.assets._assets import TradingPair +from datetime import date, datetime from six import string_types from six.moves.urllib import request -from catalyst.constants import DATE_FORMAT, SYMBOLS_URL -from catalyst.exchange.exchange_errors import ExchangeSymbolsNotFound, \ - InvalidHistoryFrequencyError, InvalidHistoryFrequencyAlias +from catalyst.constants import EXCHANGE_CONFIG_URL from catalyst.exchange.utils.serialization_utils import ExchangeJSONEncoder, \ ExchangeJSONDecoder, ConfigJSONEncoder from catalyst.utils.paths import data_root, ensure_directory, \ @@ -142,6 +140,7 @@ def get_exchange_config(exchange_name, filename=None, environ=None): except ValueError: return dict() + def save_exchange_config(exchange_name, config, filename=None, environ=None): """ Save assets into an exchange_config file. @@ -690,3 +689,33 @@ def get_candles_df(candles, field, freq, bar_count, end_dt): df.dropna(inplace=True) return df + + +def get_trades_df(trades): + df = pd.DataFrame(trades) + df.index = pd.to_datetime(df.pop('datetime')) + df.index = df.index.tz_localize('UTC') + + return df + + +def candles_from_trades(trades_df, freq): + """ + Calculate OHLCV from candles. + + Parameters + ---------- + trades_df + freq + + Returns + ------- + + """ + df = trades_df['price'].resample(freq).ohlc() # type: pd.DataFrame + df['volume'] = trades_df['amount'].resample(freq).sum() + + df.dropna(axis=0, how='all', inplace=True) + df.sort_index(inplace=True, ascending=False) + + return df diff --git a/tests/exchange/test_ccxt.py b/tests/exchange/test_ccxt.py index 16fe944f..a28b3a43 100644 --- a/tests/exchange/test_ccxt.py +++ b/tests/exchange/test_ccxt.py @@ -5,7 +5,8 @@ from catalyst.exchange.utils.stats_utils import set_print_settings from .base import BaseExchangeTestCase from catalyst.exchange.ccxt.ccxt_exchange import CCXT from catalyst.exchange.exchange_execution import ExchangeLimitOrder -from catalyst.exchange.utils.exchange_utils import get_exchange_auth +from catalyst.exchange.utils.exchange_utils import get_exchange_auth, \ + get_trades_df, candles_from_trades from catalyst.finance.order import Order log = Logger('test_ccxt') @@ -14,12 +15,13 @@ log = Logger('test_ccxt') class TestCCXT(BaseExchangeTestCase): @classmethod def setup(self): - exchange_name = 'bittrex' + exchange_name = 'binance' auth = get_exchange_auth(exchange_name) self.exchange = CCXT( exchange_name=exchange_name, key=auth['key'], secret=auth['secret'], + password=None, base_currency='usdt', ) self.exchange.init() @@ -90,6 +92,37 @@ class TestCCXT(BaseExchangeTestCase): assert trades pass + def test_validate_volume(self): + asset = self.exchange.get_asset('eng_eth') + candles = self.exchange.get_candles( + freq='1T', + assets=[asset], + bar_count=10, + ) + df = pd.DataFrame(candles[asset]) + df.set_index('last_traded', drop=True, inplace=True) + + df.drop_duplicates() + df.sort_index(inplace=True, ascending=False) + assert candles + + start_dt = df.index[-1] + trades = self.exchange.get_trades( + asset, start_dt=start_dt, my_trades=False + ) + assert trades + + trades_df = get_trades_df(trades) + df2 = candles_from_trades(trades_df, '1T') + + set_print_settings() + log.info( + 'comparing candles / resampled trades:\n{}\n{}'.format( + df, df2 + ) + ) + pass + def test_get_executed_order(self): log.info('retrieving executed order') asset = self.exchange.get_asset('eng_eth')