Install dependence & init setting

pip install cryptota -U
# Fetch data setting
CRYPTO    = "ADAUSDT"
START     = '7 day ago UTC'
END       = 'now UTC'
INTERVAL  = '1m'
# trading strategy parameter
PARAMETER = { "initial_state": 1, "delay": 500, "initial_money": 100,"max_buy":10, "max_sell":10 }
# binance api key and secret
APIKEY    = ""
APISECRET = ""
import cryptota
import vectorbt as vbt
import numpy as np
from binance import Client, ThreadedWebsocketManager, ThreadedDepthCacheManager
import matplotlib.pyplot as plt
import time
from datetime import timedelta

client = Client(APIKEY,APISECRET)
UNITS = {"s":"seconds", "m":"minutes", "h":"hours", "d":"days", "w":"weeks"}

def convert_to_seconds(s):
    count = int(s[:-1])
    unit = UNITS[ s[-1] ]
    td = timedelta(**{unit: count})
    return td.seconds + 60 * 60 * 24 * td.days

Fetch data

binance_data = vbt.BinanceData.download(
    CRYPTO,
    start=START,
    end=END,
    interval=INTERVAL
)
2021-06-01 12:13:55.045000+00:00 - 2021-06-08 12:13:00+00:00: : 21it [00:15,  1.34it/s]
price = binance_data.get()
price
Open High Low Close Volume Close time Quote volume Number of trades Taker base volume Taker quote volume
Open time
2021-06-01 12:14:00+00:00 1.6950 1.6992 1.6942 1.6970 447004.82 2021-06-01 12:14:59.999000+00:00 7.584618e+05 825 196487.27 333364.116283
2021-06-01 12:15:00+00:00 1.6970 1.6970 1.6906 1.6949 645515.99 2021-06-01 12:15:59.999000+00:00 1.093199e+06 1455 209946.61 355621.772974
2021-06-01 12:16:00+00:00 1.6948 1.7008 1.6948 1.6996 447179.45 2021-06-01 12:16:59.999000+00:00 7.594701e+05 929 260298.37 442145.740078
2021-06-01 12:17:00+00:00 1.6997 1.7004 1.6954 1.6999 435560.40 2021-06-01 12:17:59.999000+00:00 7.400373e+05 693 181832.15 308950.289983
2021-06-01 12:18:00+00:00 1.7000 1.7043 1.6994 1.7040 735351.98 2021-06-01 12:18:59.999000+00:00 1.250654e+06 763 435440.22 740536.874135
... ... ... ... ... ... ... ... ... ... ...
2021-06-08 12:09:00+00:00 1.5358 1.5374 1.5349 1.5349 194764.99 2021-06-08 12:09:59.999000+00:00 2.991422e+05 305 58719.72 90196.974988
2021-06-08 12:10:00+00:00 1.5348 1.5377 1.5348 1.5355 192415.16 2021-06-08 12:10:59.999000+00:00 2.956165e+05 369 83880.22 128853.979149
2021-06-08 12:11:00+00:00 1.5354 1.5356 1.5324 1.5333 135024.02 2021-06-08 12:11:59.999000+00:00 2.070905e+05 393 64043.56 98216.224996
2021-06-08 12:12:00+00:00 1.5333 1.5353 1.5329 1.5329 98152.81 2021-06-08 12:12:59.999000+00:00 1.505519e+05 301 34725.25 53277.500976
2021-06-08 12:13:00+00:00 1.5329 1.5354 1.5322 1.5345 128720.45 2021-06-08 12:13:59.999000+00:00 1.974064e+05 294 64370.25 98723.528574

10080 rows × 10 columns

Get technology analysis feature

ta = cryptota.TA_Features()
df_full = ta.get_all_indicators(price.copy())
/usr/local/lib/python3.7/dist-packages/pandas/core/arrays/datetimes.py:1092: UserWarning: Converting to PeriodArray/Index representation will drop timezone information.
  UserWarning,
/usr/local/lib/python3.7/dist-packages/pandas/core/arrays/datetimes.py:1092: UserWarning: Converting to PeriodArray/Index representation will drop timezone information.
  UserWarning,
df_full
open high low close volume close time quote volume number of trades taker base volume taker quote volume accbl_20 accbm_20 accbu_20 amate_lr_2 amate_sr_2 obv obv_min_2 obv_max_2 obve_4 obve_12 aobv_lr_2 aobv_sr_2 cg_10 copc_11_14_10 dec_1 dcl_20_20 dcm_20_20 dcu_20_20 efi_13 eom_14_100000000 fwma_10 isa_9 isb_26 its_9 iks_26 ics_26 inc_1 kcle_20_2 kcbe_20_2 kcue_20_2 ... macd_signal macd_histogram marketfi mass md mfi mom msw_sine msw_lead natr nvi obv_2 ppo psar pvi qstick roc rocr rsi sma stderr stoch_line stoch_ma tema tr trima trix tsf typprice ultosc vhf vidya vosc vwma wad wcprice wilders willr wma zlema
2021-06-01 12:14:00+00:00 1.6950 1.6992 1.6942 1.6970 447004.82 2021-06-01 12:14:59.999000+00:00 7.584618e+05 825 196487.27 333364.116283 NaN NaN NaN 0 0 447004.82 NaN NaN NaN NaN 0 0 NaN NaN 0 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN 1.7069 0 NaN NaN NaN ... 0.002281 0.000000 1.118556e-08 24.209488 0.003121 48.129800 0.0085 0.223103 -0.531527 0.313843 1000.000000 0.00 -0.009873 1.699200 1000.000000 -0.000020 0.005009 1.005009 52.412281 1.709100 0.001133 49.541161 44.526622 1.735238 0.0050 1.695070 -0.007178 1.708613 1.696800 44.916452 0.287729 1.700500 -23.936583 1.705185 -0.0021 1.696850 1.701406 -39.175258 1.699264 1.722700
2021-06-01 12:15:00+00:00 1.6970 1.6970 1.6906 1.6949 645515.99 2021-06-01 12:15:59.999000+00:00 1.093199e+06 1455 209946.61 355621.772974 NaN NaN NaN 0 0 -198511.17 -198511.17 447004.82 NaN NaN 0 0 NaN NaN 1 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN 1.7088 0 NaN NaN NaN ... 0.002281 0.000000 9.914549e-09 24.209488 0.003121 48.129800 0.0085 0.223103 -0.531527 0.313843 1000.000000 -645515.99 -0.009873 1.699200 998.762522 -0.000020 0.005009 1.005009 52.412281 1.709100 0.001133 49.541161 44.526622 1.735238 0.0064 1.695070 -0.007178 1.708613 1.694167 44.916452 0.287729 1.700500 -23.936583 1.705185 -0.0021 1.694350 1.701406 -39.175258 1.699264 1.722700
2021-06-01 12:16:00+00:00 1.6948 1.7008 1.6948 1.6996 447179.45 2021-06-01 12:16:59.999000+00:00 7.594701e+05 929 260298.37 442145.740078 NaN NaN NaN 0 0 248668.28 -198511.17 248668.28 NaN NaN 0 0 NaN NaN 0 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN 1.7095 1 NaN NaN NaN ... 0.002281 0.000000 1.341743e-08 24.209488 0.003121 48.129800 0.0085 0.223103 -0.531527 0.313843 1002.773025 -198336.54 0.004600 1.690600 998.762522 -0.000020 0.005009 1.005009 52.412281 1.709100 0.001133 49.541161 44.526622 1.735238 0.0060 1.695070 -0.007178 1.708613 1.698400 44.916452 0.287729 1.700500 -23.936583 1.705185 0.0027 1.698700 1.701406 -39.175258 1.699264 1.722700
2021-06-01 12:17:00+00:00 1.6997 1.7004 1.6954 1.6999 435560.40 2021-06-01 12:17:59.999000+00:00 7.400373e+05 693 181832.15 308950.289983 NaN NaN NaN 0 0 684228.68 248668.28 684228.68 2.953477e+05 NaN 0 0 NaN NaN 0 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN 1.7100 1 NaN NaN NaN ... 0.002281 0.000000 1.147946e-08 24.209488 0.003121 48.129800 0.0085 0.223103 -0.531527 0.313843 1002.950027 237223.86 0.017294 1.690600 998.762522 -0.000020 0.005009 1.005009 52.412281 1.709100 0.001133 49.541161 44.526622 1.735238 0.0050 1.695070 -0.007178 1.708613 1.698567 44.916452 0.287729 1.700500 -23.936583 1.705185 0.0072 1.698900 1.701406 -39.175258 1.699264 1.722700
2021-06-01 12:18:00+00:00 1.7000 1.7043 1.6994 1.7040 735351.98 2021-06-01 12:18:59.999000+00:00 1.250654e+06 763 435440.22 740536.874135 NaN NaN NaN 0 0 1419580.66 684228.68 1419580.66 7.450409e+05 NaN 0 0 NaN NaN 0 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN 1.7057 1 NaN NaN NaN ... 0.002281 0.000000 6.663476e-09 24.209488 0.003121 48.129800 0.0085 0.223103 -0.531527 0.313843 1002.950027 972575.84 0.046299 1.690804 1001.171444 -0.000020 0.005009 1.005009 52.412281 1.709100 0.001133 49.541161 44.526622 1.735238 0.0049 1.695070 -0.007178 1.708613 1.702567 44.916452 0.287729 1.700500 -23.936583 1.705185 0.0118 1.702925 1.701406 -39.175258 1.699264 1.722700
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
2021-06-08 12:09:00+00:00 1.5358 1.5374 1.5349 1.5349 194764.99 2021-06-08 12:09:59.999000+00:00 2.991422e+05 305 58719.72 90196.974988 1.526750 1.53594 1.545550 0 1 9874717.02 9874717.02 10069482.01 9.923282e+06 9.754150e+06 1 0 -5.504026 0.069087 1 1.5309 1.53730 1.5437 68.347855 0.000113 1.534950 NaN NaN 1.53760 1.53515 NaN 0 1.527297 1.534930 1.542564 ... 0.001966 -0.000707 1.283598e-08 24.629033 0.002407 64.255726 -0.0078 -0.704480 -0.999993 0.252595 1224.782690 9427712.20 0.085209 1.540145 738.480792 -0.000101 -0.005056 0.994944 51.777770 1.530520 0.000772 22.222222 19.205653 1.528209 0.0025 1.523310 0.019799 1.532267 1.535733 36.243592 0.288764 1.535459 7.616057 1.523341 0.1389 1.535525 1.529151 -77.192982 1.533087 1.523699
2021-06-08 12:10:00+00:00 1.5348 1.5377 1.5348 1.5355 192415.16 2021-06-08 12:10:59.999000+00:00 2.956165e+05 369 83880.22 128853.979149 1.527015 1.53605 1.545565 0 1 10067132.18 9874717.02 10067132.18 9.980822e+06 9.802301e+06 1 0 -5.502028 -0.028346 0 1.5309 1.53730 1.5437 75.076604 0.000035 1.535134 NaN NaN 1.53600 1.53515 NaN 1 1.527526 1.534985 1.542444 ... 0.001805 -0.000642 1.507158e-08 24.653524 0.002414 63.988076 -0.0025 -0.810249 -0.987358 0.247951 1225.261464 9620127.36 0.078833 1.539517 738.480792 -0.000089 -0.001625 0.998375 52.993665 1.530415 0.000777 27.192982 22.456140 1.528413 0.0029 1.523591 0.017938 1.533593 1.536000 35.549773 0.294387 1.535464 7.154508 1.523584 0.1396 1.535875 1.529278 -71.929825 1.533262 1.524001
2021-06-08 12:11:00+00:00 1.5354 1.5356 1.5324 1.5333 135024.02 2021-06-08 12:11:59.999000+00:00 2.070905e+05 393 64043.56 98216.224996 1.527090 1.53604 1.545640 0 1 9932108.16 9932108.16 10067132.18 9.961336e+06 9.822271e+06 1 0 -5.501889 -0.246307 1 1.5317 1.53770 1.5437 21.915254 -0.000616 1.534420 NaN NaN 1.53600 1.53515 NaN 0 1.527466 1.534824 1.542182 ... 0.001626 -0.000715 2.369949e-08 24.680989 0.002398 53.574181 -0.0054 -0.917228 -0.930263 0.245478 1223.505960 9485103.34 0.061508 1.538940 738.480792 -0.000106 -0.003509 0.996491 48.195135 1.530294 0.000777 19.883041 23.099415 1.528548 0.0032 1.523868 0.015890 1.533267 1.533767 37.454877 0.292711 1.535158 -7.704768 1.523850 0.1373 1.533650 1.529358 -91.228070 1.533346 1.524263
2021-06-08 12:12:00+00:00 1.5333 1.5353 1.5329 1.5329 98152.81 2021-06-08 12:12:59.999000+00:00 1.505519e+05 301 34725.25 53277.500976 1.527115 1.53602 1.545615 0 1 9833955.35 9833955.35 9932108.16 9.910384e+06 9.824069e+06 0 1 -5.501310 -0.383231 1 1.5317 1.53770 1.5437 13.175772 -0.000668 1.533827 NaN NaN 1.53570 1.53545 NaN 0 1.527527 1.534641 1.541756 ... 0.001436 -0.000763 2.445167e-08 24.624058 0.002265 48.507894 -0.0049 -0.984464 -0.820279 0.239186 1223.186778 9386950.53 0.045153 1.538409 738.480792 -0.000099 -0.003186 0.996814 47.355527 1.530180 0.000777 14.035088 20.370370 1.528668 0.0024 1.524142 0.013719 1.533280 1.533700 29.917056 0.297110 1.534829 -11.014302 1.523998 0.1349 1.533500 1.529429 -94.736842 1.533411 1.524517
2021-06-08 12:13:00+00:00 1.5329 1.5354 1.5322 1.5345 128720.45 2021-06-08 12:13:59.999000+00:00 1.974064e+05 294 64370.25 98723.528574 1.527130 1.53612 1.545655 0 1 9962675.80 9833955.35 9962675.80 9.931301e+06 9.845393e+06 0 1 -5.500205 -0.451871 0 1.5322 1.53795 1.5437 40.715336 -0.000790 1.534067 NaN NaN 1.53495 1.53545 NaN 1 1.527581 1.534628 1.541674 ... 0.001268 -0.000671 2.486007e-08 24.362265 0.002056 45.553964 0.0004 -0.997329 -0.653573 0.236765 1223.186778 9515670.98 0.040141 1.537920 739.251599 -0.000080 0.000261 1.000261 51.030420 1.530085 0.000780 11.345029 15.087719 1.528833 0.0032 1.524412 0.011789 1.534080 1.534033 37.021815 0.295063 1.534781 -14.048379 1.524136 0.1372 1.534150 1.529530 -80.000000 1.533537 1.524803

10080 rows × 151 columns

Purpose a strategy

def buy_stock(
    real_movement,
    delay = 5,
    initial_state = 1,
    initial_money = 10000,
    max_buy = 1,
    max_sell = 1,
    print_log=True
):
    """
    real_movement = actual movement in the real world
    delay = how much interval you want to delay to change our decision from buy to sell, vice versa
    initial_state = 1 is buy, 0 is sell
    initial_money = 1000, ignore what kind of currency
    max_buy = max quantity for share to buy
    max_sell = max quantity for share to sell
    """
    starting_money = initial_money
    delay_change_decision = delay
    current_decision = 0
    state = initial_state
    current_val = real_movement[0]
    states_sell = []
    states_buy = []
    states_entry = []
    states_exit = []
    current_inventory = 0

    def buy(i, initial_money, current_inventory):
        shares = initial_money // real_movement[i]
        if shares < 1:
            if print_log:
                print(
                    'day %d: total balances %f, not enough money to buy a unit price %f'
                    % (i, initial_money, real_movement[i])
                )
        else:
            if shares > max_buy:
                buy_units = max_buy
            else:
                buy_units = shares
            initial_money -= buy_units * real_movement[i]
            current_inventory += buy_units
            if print_log:
                print(
                    'day %d: buy %d units at price %f, total balance %f'
                    % (i, buy_units, buy_units * real_movement[i], initial_money)
                )
            states_buy.append(0)
        return initial_money, current_inventory

    if state == 1:
        initial_money, current_inventory = buy(
            0, initial_money, current_inventory
        )

    for i in range(0, real_movement.shape[0], 1):
        sentry = False
        sexit = False
        if real_movement[i] < current_val and state == 0:
            if current_decision < delay_change_decision:
                current_decision += 1
            else:
                state = 1
                initial_money, current_inventory = buy(
                    i, initial_money, current_inventory
                )
                current_decision = 0
                states_buy.append(i)
                sentry = True
                
        if real_movement[i] > current_val and state == 1:
            if current_decision < delay_change_decision:
                current_decision += 1
            else:
                state = 0

                if current_inventory == 0:
                    if print_log:
                        print('day %d: cannot sell anything, inventory 0' % (i))
                else:
                    if current_inventory > max_sell:
                        sell_units = max_sell
                    else:
                        sell_units = current_inventory
                    current_inventory -= sell_units
                    total_sell = sell_units * real_movement[i]
                    initial_money += total_sell
                    try:
                        invest = (
                            (real_movement[i] - real_movement[states_buy[-1]])
                            / real_movement[states_buy[-1]]
                        ) * 100
                    except:
                        invest = 0
                    if print_log:
                        print(
                            'day %d, sell %d units at price %f, investment %f %%, total balance %f,'
                            % (i, sell_units, total_sell, invest, initial_money)
                        )

                current_decision = 0
                states_sell.append(i)
                sexit = True
        states_entry.append(sentry)
        states_exit.append(sexit)
        current_val = real_movement[i]
        
    invest = ((initial_money - starting_money) / starting_money) * 100
    total_gains = initial_money - starting_money
    return states_buy, states_sell,states_entry,states_exit, total_gains, invest

Backtest

states_buy, states_sell, states_entry, states_exit, total_gains, invest = buy_stock(df_full.close,**PARAMETER)
day 0: buy 10 units at price 16.970000, total balance 83.030000
day 975, sell 10 units at price 17.785000, investment 4.802593 %, total balance 100.815000,
day 2045: buy 10 units at price 17.633000, total balance 83.182000
day 3030, sell 10 units at price 18.204000, investment 3.238246 %, total balance 101.386000,
day 4047: buy 10 units at price 16.601000, total balance 84.785000
day 5016, sell 10 units at price 17.141000, investment 3.252816 %, total balance 101.926000,
day 6117: buy 10 units at price 16.797000, total balance 85.129000
day 7112, sell 10 units at price 16.800000, investment 0.017860 %, total balance 101.929000,
day 8187: buy 10 units at price 17.225000, total balance 84.704000
day 9208, sell 10 units at price 15.926000, investment -7.541364 %, total balance 100.630000,
close = df_full['close']
fig = plt.figure(figsize = (15,5))
plt.plot(close, color='r', lw=2.)
plt.plot(close, '^', markersize=10, color='m', label = 'buying signal', markevery = states_buy)
plt.plot(close, 'v', markersize=10, color='k', label = 'selling signal', markevery = states_sell)
plt.legend()
plt.show()
fees = 0.001
try:
  fees = client.get_trade_fee(symbol=CRYPTO)[0]['makerCommission']
except:
  pass
portfolio_kwargs = dict(size=np.inf, fees=float(fees), freq=INTERVAL)
portfolio = vbt.Portfolio.from_signals(df_full['close'], states_entry, states_exit, **portfolio_kwargs)
portfolio.plot().show()