scrtlabs / catalyst

An Algorithmic Trading Library for Crypto-Assets in Python
http://enigma.co
Apache License 2.0
2.49k stars 725 forks source link

Weird behaviour of algo on bittrex exchange. #100

Closed blitzarx1 closed 6 years ago

blitzarx1 commented 6 years ago

Dear Catalyst Maintainers,

Before I tell you about my issue, let me describe my environment:

Environment

Now that you know a little about me, let me tell you about the issue I am having:

Description of Issue

Here is how you can reproduce this issue on your machine:

Reproduction Steps

  1. make sure u have plotly installed (pip install plotly)
  2. ingest market data
  3. run the script (python volume_bittrex.py)

What steps have you taken to resolve this already?

Checked the code for obvious errors and general logic check.

Anything else?

INSERTING THE CODE :

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):

        # use pairs valid on bittrex
    pairs_str = [
        'wings_eth', 'dyn_btc', 'ok_btc', 'seq_btc', 'aby_btc', 'dmd_btc', 'meme_btc',
        'club_btc', 'dnt_eth', 'tx_btc', 'powr_btc', 'nmr_btc', 'powr_eth', 'vib_btc',
        'neo_eth', 'trust_btc', 'mana_eth', 'waves_eth', 'dgb_eth', 'xem_btc', 'dgd_eth',
        'emc2_btc', 'golos_btc', 'ltc_usdt', 'vox_btc', 'synx_btc', 'btc_usdt', 'exp_btc',
        'egc_btc', 'cvc_btc', 'xmr_btc', 'etc_btc', 'strat_btc', 'ptoy_btc', 'eth_btc',
        'cpc_btc', 'cloak_btc', 'clam_btc', 'snt_btc', 'trst_btc', 'snt_eth', 'bcc_btc',
        'cann_btc', 'swt_btc', 'blk_btc', '1st_eth', 'dash_btc', 'qtum_eth', 'fun_btc',
        'maid_btc', 'zen_btc', 'aeon_btc', 'neo_btc', 'mco_eth', 'btg_btc', 'mona_btc',
        'edg_btc', 'ebst_btc', 'start_btc', 'flo_btc', 'myst_btc', 'mco_btc',
        'wings_btc', 'byc_btc', 'mtl_btc', 'ada_btc', 'pdc_btc', 'erc_btc', 'cvc_eth', 'xmr_eth',
        'crb_btc', 'ltc_eth', 'adt_btc', 'block_btc', 'vtr_btc', 'dgb_btc', 'etc_eth', 'rise_btc',
        'ptoy_eth', 'adx_btc', 'via_btc', 'pink_btc', 'bnt_btc', 'gnt_eth', 'dtb_btc', 'nxs_btc',
        'agrs_btc', 'geo_btc', 'shift_btc', 'salt_btc', 'cfi_eth', 'xwc_btc', 'nxc_btc',
        'bat_btc', 'xlm_btc', 'xem_eth', 'dope_btc', 'hmq_eth', 'adt_eth', 'pivx_btc', 'bnt_eth',
        'adx_eth', 'ark_btc', 'dct_btc', 'zec_btc', 'mue_btc', 'amp_btc', 'ada_eth', 'safex_btc',
        'omni_btc', 'ptc_btc', 'lgd_btc', 'ardr_btc', 'sngls_btc', 'xlm_eth', 'sls_btc', 'bat_eth',
        'salt_eth', 'gnt_btc', 'cfi_btc', 'sc_eth', 'coval_btc', 'vib_eth', 'omg_btc', 'bcc_eth',
        'xvc_btc', 'rads_btc', 'gbg_btc', 'xvg_btc', 'nmr_eth', 'efl_btc', 'bay_btc', 'dgd_btc',
        'dnt_btc', 'sngls_eth', 'gno_btc', 'eng_eth', 'gcr_btc', 'xel_btc', 'storj_eth', 'thc_btc',
        'btcd_btc', 'btg_eth', 'nbt_btc', 'fct_eth', 'neo_usdt', 'hmq_btc', 'sib_btc', 'lun_btc',
        'fldc_btc', 'trst_eth', 'lbc_btc', 'myst_eth', 'eng_btc', 'pot_btc', 'burst_btc',
        '2give_btc', 'grc_btc', 'slr_btc', 'infx_btc', 'ant_btc', 'tks_btc', 'grs_btc',
        'bcc_usdt', 'dcr_btc', 'xdn_btc', 'lun_eth', 'qtum_btc', 'doge_btc', 'lmc_btc',
        'blitz_btc', 'gbyte_btc', 'xrp_eth', 'ant_eth', 'btg_usdt', 'storj_btc', 'xrp_usdt', 'mln_btc',
        'gup_btc', 'rcn_eth', 'iop_btc', 'neos_btc', 'sbd_btc', 'xaur_btc', 'xmy_btc', 'swift_btc',
        'steem_btc', 'zec_usdt', 'ioc_btc', 'rby_btc', 'xmg_btc', 'music_btc', 'ubq_btc', 'qrl_eth',
        'snrg_btc', 'enrg_btc', 'gld_btc', 'ion_btc', 'kore_btc', 'crb_eth', 'spr_btc', 'cure_btc',
        'fct_btc', 'nlg_btc', 'kmd_btc', 'bsd_btc', 'dash_usdt', 'fair_btc', 'dash_eth', 'qwark_btc',
        'emc_btc', 'lsk_btc', 'gam_btc', 'part_btc', 'apx_btc', 'mtl_eth', 'bcy_btc', 'excl_btc',
        'sphr_btc', 'pay_btc', 'ftc_btc', 'vrm_btc', 'bitb_btc', 'tix_eth', 'tix_btc',
        'zec_eth', 'gno_eth', 'gup_eth', 'xst_btc', 'lgd_eth', 'rep_btc', 'ltc_btc', 'xmr_usdt',
        'rlc_eth', 'ppc_btc', 'rlc_btc', 'waves_btc', 'brk_btc', 'qrl_btc', '1st_btc', 'nav_btc',
        'trig_btc', 'vtc_btc', 'fun_eth', 'nxt_btc', 'xzc_btc', 'brx_btc', 'sys_btc',
        'crw_btc', 'pkb_btc', 'omg_usdt', 'rdd_btc', 'game_btc', 'aur_btc', 'unb_btc', 'eth_usdt',
        'etc_usdt', 'pay_eth', 'xcp_btc', 'mana_btc', 'omg_eth', 'mer_btc', 'strat_eth', 'zcl_btc',
        'rcn_btc', 'rep_eth', 'vrc_btc', 'incnt_btc', 'xrp_btc'
    ]

    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_bittrex 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

            # print proto_weights

            # 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))])

                # print turnover

                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_bittrex.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_bittrex 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 bittrex 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_bittrex.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=100000.0,
        initialize=initialize,
        handle_data=handle_data,
        analyze=analyze,
        exchange_name='bittrex',
        data_frequency='daily',
        base_currency='btc',
        live=False,
        live_graph=False,
        algo_namespace='volume_bittrex')

Sincerely, bl17zar .

fredfortier commented 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.

blitzarx1 commented 6 years ago

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.

blitzarx1 commented 6 years ago

@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 ...

fredfortier commented 6 years ago

Yes, thanks! I'll still looking into this coming from a slightly different angle. I will post an update today.

blitzarx1 commented 6 years ago

Ok)

blitzarx1 commented 6 years ago

@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)

fredfortier commented 6 years ago

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 .

blitzarx1 commented 6 years ago

@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.

fredfortier commented 6 years ago

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 .

fredfortier commented 6 years ago

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.