Closed blitzarx1 closed 6 years ago
Thanks for the detailed example. I will try to run it see what might cause the discrepancy. I'll do my best to get back to you within 24H.
Ok. Thank you. P.S. Sorry there is lot of stuff in the code not connected with the issue and logic of the algorithm (like logging and plotting), hope it is not very distractive.
@fredfortier For comparison I can provide the same algo for poloniex exchange. And you will be able to see the difference in result. Thanks for your time ;)
from catalyst.api import order_target_percent, record, symbol
from catalyst import run_algorithm
from logbook import Logger
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import plotly as py
import plotly.graph_objs as go
import os
log = Logger('market_cap')
def initialize(context):
# set_commission()
# use pairs valid on poloniex
pairs_str = [
'rep_usdt', 'gno_btc', 'xvc_btc', 'pink_btc', 'sys_btc', 'emc2_btc',
'rads_btc', 'sc_btc', 'maid_btc', 'bch_btc', 'gnt_btc', 'bcn_btc', 'rep_btc',
'bcy_btc', 'cvc_btc', 'nxt_xmr', 'zec_usdt', 'fct_btc', 'gas_btc', 'pot_btc',
'eth_usdt', 'btc_usdt', 'lbc_btc', 'dcr_btc', 'etc_usdt', 'omg_eth', 'amp_btc',
'xpm_btc', 'nxt_btc', 'vtc_btc', 'steem_eth', 'blk_xmr', 'pasc_btc', 'zec_xmr',
'grc_btc', 'nxc_btc', 'btcd_btc', 'ltc_btc', 'dash_btc', 'storj_btc', 'zec_eth',
'zec_btc', 'burst_btc', 'zrx_eth', 'bela_btc', 'steem_btc', 'etc_btc', 'eth_btc',
'huc_btc', 'strat_btc', 'lsk_btc', 'exp_btc', 'clam_btc', 'rep_eth', 'dash_xmr',
'cvc_eth', 'bch_usdt', 'zrx_btc', 'dash_usdt', 'blk_btc', 'xrp_btc', 'nxt_usdt',
'neos_btc', 'omg_btc', 'bts_btc', 'doge_btc', 'gnt_eth', 'sbd_btc', 'gno_eth',
'xcp_btc', 'ltc_usdt', 'btm_btc', 'xmr_usdt', 'lsk_eth', 'omni_btc', 'nav_btc',
'fldc_btc', 'ppc_btc', 'xbc_btc', 'dgb_btc', 'btcd_xmr', 'vrc_btc', 'ric_btc',
'str_btc', 'maid_xmr', 'xmr_btc', 'via_btc', 'xem_btc', 'nmc_btc', 'etc_eth',
'ltc_xmr', 'ardr_btc', 'gas_eth', 'flo_btc', 'xrp_usdt', 'game_btc', 'bch_eth',
'bcn_xmr', 'str_usdt'
]
context.pairs = map(symbol, pairs_str)
# pairs volume object
context.vol = np.zeros(len(context.pairs))
# set the rebalance period
context.rebalance_period = 7
# set day counter
context.i = 0
# portfolio size
context.portfolio_active_size = 10
# active pairs for the week
context.top_pairs = []
# for turnover routine
context.last_week_weights = []
# turnover threshold
context.turnover_threshold = 0.05
# logging
log_path = '../logs/'
if not os.path.isdir(log_path):
os.mkdir(log_path)
context.f = open('../logs/algos_log.txt', 'a')
context.f.write(
'\n\n........................ starting volume_poloniex algorithm ........................\n')
# spent for today
context.total_spent = 0
def handle_data(context, data):
# current date
curr_date = context.blotter.current_dt.strftime('%Y-%m-%d %H:%M:%S')
context.f.write('\n\n date is %s\n' % curr_date)
# reset spent amount
context.total_spent = 0
# log cash
context.f.write('todays cash %s;\n' % context.portfolio.cash)
# log portf value
context.f.write('portfolio pairs value today is %s;\n' %
np.sum([data.current(pair, 'price') * context.portfolio.positions[pair].amount
for pair in context.portfolio.positions]))
# log pair value
for pair in context.portfolio.positions:
context.f.write('for %s is %s;\n' %
(pair.symbol, data.current(pair, 'price') * context.portfolio.positions[pair].amount))
# for every pair volume
for i in xrange(len(context.pairs)):
context.vol[i] += data.current(context.pairs[i], 'volume')
# check if it's time to rebalance the portfolio
if context.i % context.rebalance_period == 0 or context.i == 0:
# log initial info
context.f.write('\n\n WEEK %s, DATE %s \n' %
(int(np.ceil(context.i / 7)), str(curr_date)))
context.f.write('CURRENT PORTFOLIO VALUE IS %s \n' %
context.portfolio.portfolio_value)
context.f.write('CURRENT CASH AMOUNT IS %s \n' %
context.portfolio.cash)
# creating sorted array of pairs by the highest volume
for_sort = []
for i in xrange(len(context.pairs)):
curr_vol_curr_pair = [context.vol[i], context.pairs[i]]
for_sort.append(curr_vol_curr_pair)
sorted_pairs = sorted(for_sort, key=lambda x: x[0], reverse=True)
# choose top 10 from the sorted array of pairs by the highest volume
context.top_pairs = [context.pairs[context.pairs.index(
sorted_pairs[i][1])] for i in xrange(context.portfolio_active_size)]
# sell all pairs that are not in current portfolio
for pair in context.portfolio.positions:
if not pair in context.top_pairs and not context.i == 0:
order_target_percent(pair, 0)
# log sold
context.f.write('Sold %s shares of %s for %s in total of %s usd;\n' %
(context.portfolio.positions[pair].amount, pair.symbol, data.current(pair, 'price'), context.portfolio.positions[pair].amount * data.current(pair, 'price')))
# portfolio rebalancing routine
if not context.i < 7:
# compute the weights according to week median.
# can start computing weights only after first week has passed,
# due to necessity to gather information on volume.
median_vol = [np.mean(data.history(
pair, 'volume', bar_count=7, frequency='1d')) for pair in context.top_pairs]
total_median_vol = np.sum(median_vol)
proto_weights = median_vol / total_median_vol
# computing turnover
if len(context.last_week_weights) > 0:
turnover = np.array([np.abs((context.last_week_weights[i] - proto_weights[i]) / context.last_week_weights[i])
for i in xrange(len(proto_weights))])
if (lambda x: x < context.turnover_threshold)(turnover).any():
# recalculating weights
mask_indxs, = np.where(
(lambda x: x < context.turnover_threshold)(turnover) == True)
pairs_info_arr = [context.pairs[
i].symbol for i in xrange(len(mask_indxs))]
turnover_info_arr = [turnover[mask_indxs[i]]
for i in xrange(len(mask_indxs))]
# log failed pairs
context.f.write('Recalculating weights as %s has turnover less than %s (%s);\n' % (
pairs_info_arr, context.turnover_threshold, turnover_info_arr))
# norm new weights
corrected_median_vol = [0.0 if i in mask_indxs else median_vol[
i] for i in xrange(len(median_vol))]
weights = corrected_median_vol / \
np.sum(corrected_median_vol)
else:
weights = proto_weights
else:
weights = proto_weights
# rebalance portfolio according to weights and current cash amount
for g in range(len(context.top_pairs)):
curr_pair = context.top_pairs[g]
# check if pair can be traded on exchange
if data.can_trade(curr_pair):
price = data.current(curr_pair, 'price')
# count the amount required for order
amount = (context.portfolio.portfolio_value *
weights[g]) / data.current(curr_pair, 'price')
price_for_amount = amount * price
# make the order
# log current amount in portfolio
context.f.write('amount in portfolio of %s is %s;\n' % (
curr_pair.symbol, context.portfolio.positions[curr_pair].amount))
# order(curr_pair, amount)
order_target_percent(curr_pair, weights[g])
context.total_spent += price_for_amount
# log the amount pair was traded for
context.f.write('%s was traded for the amount %s for %s usd;\n' %
(curr_pair.symbol, amount, price_for_amount))
else:
# The pair has not been traded due to exchange reasons
context.f.write('%s has not been traded due to exchange reasons;\n' %
curr_pair.symbol)
# remember this week weights for turnover routine
context.last_week_weights = weights
else:
# cant trade cause its first week and we dont know the volume for
# previous week
context.f.write(
'Not making any trades because it is first week and we dont have volume statistics\n')
# record the data
record(cash=context.portfolio.cash,
btc=data.current(symbol('btc_usdt'), 'price'))
# log total cash spent
context.f.write('total cash spent for today is %s;\n\n' %
context.total_spent)
# increment day counter
context.i += 1
def analyze(context, perf):
# check the presence of required folders
performance_path = '../performance/'
if not os.path.isdir(performance_path):
os.mkdir(performance_path)
# log results
performance = {'percent': [], 'std': [], 'time': []}
context.f.write('------====== PERFORMANCE SECTION ======------\n')
for i in xrange(int(np.ceil(len(perf.portfolio_value) / 7.0))):
if not i == 0:
res = ((perf.portfolio_value[i * 7] - perf.portfolio_value[(i - 1) * 7]
) / (perf.portfolio_value[(i - 1) * 7])) * 100
std = np.std(perf.portfolio_value[(i - 1) * 7:i * 7])
context.f.write(
'WEEK %s PERFORMANCE: %s percents of previous week with standard deviation %s;\n' % (i, res, std))
performance['percent'].append(res)
performance['std'].append(std)
performance['time'].append(perf.portfolio_value[
perf.portfolio_value == perf.portfolio_value[i * 7]].index.tolist()[0])
total = ((perf.portfolio_value[len(perf.portfolio_value) - 1] -
context.portfolio.starting_cash) / context.portfolio.starting_cash) * 100
df_performance = pd.DataFrame(data=performance, index = performance['time'])
df_performance.to_excel(
'../performance/volume_poloniex.xlsx', index=True, index_label='time', columns = ['percent','std'])
# log total
context.f.write(
'\nTOTAL RETURN IS %s percents of starting cash;\n' % total)
# close log file
context.f.write(
'\n\n........................ end of volume_poloniex algorithm ........................')
context.f.close()
trace = go.Scatter(x=perf.portfolio_value.index,
y=perf.portfolio_value, name='portf val')
trace1 = go.Scatter(x=perf.portfolio_value.index, y=perf.btc,
name='btc/usd', yaxis='y2')
data = go.Data([trace, trace1])
layout = dict(
title='performance of poloniex volume algorithm',
xaxis=dict(
rangeselector=dict(
buttons=list([
dict(count=1,
label='1w',
step='week',
stepmode='backward'),
dict(step='all')
])
),
rangeslider=dict(),
type='date',
title='time'
),
yaxis=dict(title='portfolio value'),
yaxis2=dict(title='btc/usd', overlaying='y',
side='right')
)
fig = go.Figure(data=data, layout=layout)
# save graph
py.offline.plot(fig, filename='../performance/volume_poloniex.html')
if __name__ == '__main__':
start_date = pd.to_datetime('2017-05-20', utc=True)
end_date = pd.to_datetime('2017-11-20', utc=True)
performance = run_algorithm(
start=start_date,
end=end_date,
capital_base=10000000.0,
initialize=initialize,
handle_data=handle_data,
analyze=analyze,
exchange_name='poloniex',
data_frequency='daily',
base_currency='usd',
live=False,
live_graph=False,
algo_namespace='volume_poloniex')
Hope it will help ...
Yes, thanks! I'll still looking into this coming from a slightly different angle. I will post an update today.
Ok)
@fredfortier Hey there! How are u? any news on the issue? if u need cleaner script with the same logic and same catalyst functions without log and other stuff wrappers i can send it in a while. Just give me some info)
Hi - Sorry for the delay. I got stuck with something else. Yes, if you could isolate the issue it would be greatly appreciated and should lead to a faster resolution.
On Mon, Dec 18, 2017 at 11:20 AM bl17zar notifications@github.com wrote:
@fredfortier https://github.com/fredfortier Hey there! How are u? any news on the issue? if u need cleaner script with the same logic and same catalyst functions without log and other stuff wrappers i can send it in a while. Just give me some info)
— You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub https://github.com/enigmampc/catalyst/issues/100#issuecomment-352476253, or mute the thread https://github.com/notifications/unsubscribe-auth/ABZ-QotYPn2cql0MnOcukvhke7DLe3tMks5tBpCzgaJpZM4RBK3H .
@fredfortier Ok, np) I see, there is a lot of happening around catalyst now. I'll post here edited version of the script in a day.
Thanks for your understanding. We're doing a lot of work on historical data which might resolve your issue in a roundabout way. Nevertheless, we'll make sure to replicate your specific use case to confirm issue resolution.
On Mon, Dec 18, 2017 at 12:45 PM bl17zar notifications@github.com wrote:
@fredfortier https://github.com/fredfortier Ok, np) I see, there is a lot of happening around catalyst now. I'll post here edited version of the script in a day.
— You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub https://github.com/enigmampc/catalyst/issues/100#issuecomment-352501674, or mute the thread https://github.com/notifications/unsubscribe-auth/ABZ-Qj-Y-XSm6YT3i2kIjL-KUQYhzbEnks5tBqS0gaJpZM4RBK3H .
We've done a lot of testing in this area and some adjustments. I'm going to resolve this but please reopen if anything still looks off.
Dear Catalyst Maintainers,
Before I tell you about my issue, let me describe my environment:
Environment
ccxt 1.10.374
certifi 2017.11.5
multipledispatch 0.4.9
numpy 1.13.3
pandas 0.19.2
plotly 2.2.2
python-dateutil 2.6.1
pytz 2017.3
requests 2.18.4
scipy 1.0.0
setuptools 38.2.4
statsmodels 0.8.0
toolz 0.8.2
zlib 1.2.11 hf3cbc9b_2
Now that you know a little about me, let me tell you about the issue I am having:
Description of Issue
What did you expect to happen? I expect the algo to behave at least the same way like it behaves on poloniex and bitfinex. The behaviour seems very weird to me under such market conditions and the negative return is totally unexpected. I have no idea what can cause it. Need your guidance and assistance please.
What happened instead? Got instantaneous fall of portfolio value right after first week which continued for the rest of the period.
Here is how you can reproduce this issue on your machine:
Reproduction Steps
What steps have you taken to resolve this already?
Checked the code for obvious errors and general logic check.
Anything else?
INSERTING THE CODE :
Sincerely, bl17zar .