Skip to content

Commit

Permalink
Get_Wallet, Broker Mapping, Partial Candle Update
Browse files Browse the repository at this point in the history
Added ability to get a wallet
Added an option to drop the most recent candle
Improved broker mapping so that you only need to specify the parts you want to change. 
Updated various doc strings
Removed balance checks - Not needed since we have get wallet now
  • Loading branch information
Dave-Vallance committed Sep 6, 2018
1 parent daf4047 commit 944353a
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 23 deletions.
34 changes: 25 additions & 9 deletions ccxtbt/ccxtbroker.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,12 @@ class CCXTBroker(with_metaclass(MetaCCXTBroker, BrokerBase)):
Added a new mappings parameter to the script with defaults.
self.balance_checks can be overwritten in the strategy to stop making a getbalance()
call. Useful when backfilling. It should be set by the strategy to pause and also
restart the checks
Added a new get_wallet_balance method. This will allow manual checking of the balance.
The method will allow setting parameters. Useful for getting margin balances
Modified getcash() and getvalue():
Backtrader will call getcash and getvalue before and after next, slowing things down
with rest calls. As such, th
The broker mapping should contain a new dict for order_types and mappings like below:
Expand Down Expand Up @@ -96,9 +99,16 @@ class CCXTBroker(with_metaclass(MetaCCXTBroker, BrokerBase)):

def __init__(self, broker_mapping=None, **kwargs):
super(CCXTBroker, self).__init__()

if broker_mapping is not None:
self.order_types = broker_mapping['order_types']
self.mappings = broker_mapping['mappings']
try:
self.order_types = broker_mapping['order_types']
except KeyError: # Might not want to change the order types
pass
try:
self.mappings = broker_mapping['mappings']
except KeyError: # might not want to change the mappings
pass

#self.o = oandav20store.OandaV20Store(**kwargs)
#self.store = CCXTStore(exchange, config, retries)
Expand All @@ -113,17 +123,18 @@ def __init__(self, broker_mapping=None, **kwargs):

self.open_orders = list()

self.balance_checks = True

self.startingcash = self.store._cash
self.startingvalue = self.store._value

def get_wallet_balance(self, currency, params=None):
balance = self.store.get_wallet_balance(currency, params=params)
cash = balance['free'][currency]
value = balance['total'][currency]
return cash, value

def getcash(self):
# Get cash seems to always be called before get value
# Therefore it makes sense to add getbalance here.
if self.balance_checks:
self.store.getbalance(self.currency)
#return self.store.getcash(self.currency)
return self.store._cash

Expand Down Expand Up @@ -197,6 +208,11 @@ def cancel(self, order):
return order

ccxt_order = self.store.cancel_order(oID)
print('CCXT Order')
print(ccxt_order)
print('Value Received: {}'.format(ccxt_order[self.mappings['canceled_order']['key']]))
print('Value Expected: {}'.format(self.mappings['canceled_order']['value']))

if ccxt_order[self.mappings['canceled_order']['key']] == self.mappings['canceled_order']['value']:
self.open_orders.remove(order)
order.cancel()
Expand Down
56 changes: 50 additions & 6 deletions ccxtbt/ccxtfeed.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,23 @@ class CCXTFeed(with_metaclass(MetaCCXTFeed, DataBase)):
- ``backfill_start`` (default: ``True``)
Perform backfilling at the start. The maximum possible historical data
will be fetched in a single request.
Changes From Ed's pacakge
- Added option to send some additional fetch_ohlcv_params. Some exchanges (e.g Bitmex)
support sending some additional fetch parameters.
- Added drop_newest option to avoid loading incomplete candles where exchanges
do not support sending ohlcv params to prevent returning partial data
"""

params = (
('historical', False), # only historical download
('backfill_start', False), # do backfilling at the start
('fetch_ohlcv_params', {}),
('ohlcv_limit', 20)
('ohlcv_limit', 20),
('drop_newest', False),
('debug', False)
)

_store = CCXTStore
Expand Down Expand Up @@ -100,7 +110,11 @@ def _load(self):
return self._load_ticks()
else:
self._fetch_ohlcv()
return self._load_ohlcv()
ret = self._load_ohlcv()
if self.p.debug:
print('---- LOAD ----')
print('{} Load OHLCV Returning: {}'.format(datetime.utcnow(), ret))
return ret

elif self._state == self._ST_HISTORBACK:
ret = self._load_ohlcv()
Expand Down Expand Up @@ -134,19 +148,49 @@ def _fetch_ohlcv(self, fromdate=None):
while True:
dlen = len(self._data)

for ohlcv in sorted(self.store.fetch_ohlcv(self.symbol, timeframe=granularity,
since=since, limit=limit, params=self.p.fetch_ohlcv_params)):

if self.p.debug:
# TESTING
since_dt = datetime.utcfromtimestamp(since // 1000) if since is not None else 'NA'
print('---- NEW REQUEST ----')
print('{} - Requesting: Since TS {} Since date {} granularity {}, limit {}, params'.format(datetime.utcnow(),since, since_dt, granularity, limit, self.p.fetch_ohlcv_params))
data = sorted(self.store.fetch_ohlcv(self.symbol, timeframe=granularity,
since=since, limit=limit, params=self.p.fetch_ohlcv_params))
try:
for i, ohlcv in enumerate(data):
tstamp, open_, high, low, close, volume = ohlcv
print('{} - Data {}: {} - TS {} Time {}'.format(datetime.utcnow(), i, datetime.utcfromtimestamp(tstamp // 1000), tstamp, (time.time() * 1000)))
# ------------------------------------------------------------------
except IndexError:
print('Index Error: Data = {}'.format(data))
print('---- REQUEST END ----')
else:

data = sorted(self.store.fetch_ohlcv(self.symbol, timeframe=granularity,
since=since, limit=limit, params=self.p.fetch_ohlcv_params))

# Check to see if dropping the latest candle will help with
# exchanges which return partial data
if self.p.drop_newest:
del data[-1]

for ohlcv in data:

#for ohlcv in sorted(self.store.fetch_ohlcv(self.symbol, timeframe=granularity,
# since=since, limit=limit, params=self.p.fetch_ohlcv_params)):

if None in ohlcv:
continue

tstamp = ohlcv[0]

# Prevent from loading incomplete data
if tstamp > (time.time() * 1000):
continue
#if tstamp > (time.time() * 1000):
# continue

if tstamp > self._last_ts:
if self.p.debug:
print('Adding: {}'.format(ohlcv))
self._data.append(ohlcv)
self._last_ts = tstamp

Expand Down
21 changes: 13 additions & 8 deletions ccxtbt/ccxtstore.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,12 @@ def __call__(cls, *args, **kwargs):


class CCXTStore(with_metaclass(MetaSingleton, object)):
'''API provider for CCXT feed and broker classes.'''
'''API provider for CCXT feed and broker classes.
Added a new get_wallet_balance method. This will allow manual checking of the balance.
The method will allow setting parameters. Useful for getting margin balances
'''

# Supported granularities
_GRANULARITIES = {
Expand Down Expand Up @@ -129,17 +134,17 @@ def retry_method(self, *args, **kwargs):


@retry
def getbalance(self, currency):
def get_wallet_balance(self, currency, params=None):
balance = self.exchange.fetch_balance(params)
return balance

@retry
def get_balance(self, currency):
balance = self.exchange.fetch_balance()
self._cash = balance['free'][currency]
self._value = balance['total'][currency]

#@retry
#def getvalue(self, currency):
# return self._value
# #return self.exchange.fetch_balance()['total'][currency]

#@retry
@retry
def getposition(self, currency):
return self._value
#return self.getvalue(currency)
Expand Down

0 comments on commit 944353a

Please sign in to comment.