Last active
December 6, 2018 00:20
-
-
Save anthonytxie/ad1f493ea9bc36bd86a81697d5fc7493 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"cells": [ | |
{ | |
"cell_type": "code", | |
"execution_count": 8, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"# Define percentages I want in floats\n", | |
"from datetime import datetime, timedelta\n", | |
"import pandas as pd\n", | |
"import numpy as np \n", | |
"from pandas.tseries.offsets import *\n", | |
"\n", | |
"df = pd.read_csv('/price-history.csv', index_col=0)\n", | |
"df.index = pd.to_datetime(df.index)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 18, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"def get_n_random_assets(n, df): \n", | |
" return pd.concat([df.sample(n=n-1, axis=1), btc_df], axis=1)\n", | |
"\n", | |
"\n", | |
"def gen_rebalancing_dates(date, end_date, rebalancing_period):\n", | |
" rebalancing_periods = []\n", | |
" while date < end_date:\n", | |
" date = date + rebalancing_period\n", | |
" rebalancing_periods.append(date)\n", | |
" return rebalancing_periods\n", | |
"\n", | |
"def annualize_returns(series, years):\n", | |
" return (((series[-1]/ series[0])) ** (1/years))-1\n", | |
"\n", | |
"\n", | |
"def set_initial_allocation(tickers):\n", | |
" allocation = {}\n", | |
" for ticker in tickers:\n", | |
" allocation[ticker] = 1/len(tickers)\n", | |
" return pd.Series(allocation)\n", | |
"\n", | |
"def set_min_trading_sizes(tickers, min_btc_amount):\n", | |
" trading_limits_btc = {}\n", | |
" for ticker in tickers:\n", | |
" trading_limits_btc[ticker] = min_btc_amount\n", | |
" return pd.Series(trading_limits_btc)\n", | |
" \n", | |
"\n", | |
"def calc_returns(df, period ):\n", | |
" returns = {}\n", | |
" tickers = df.columns \n", | |
" for ticker in tickers:\n", | |
" returns[ticker] = annualize_returns(df[ticker], period)\n", | |
" return returns\n", | |
"\n", | |
"def calc_max_return_difference(df, years):\n", | |
" max_return = 0\n", | |
" for column in df:\n", | |
" returns = annualize_returns(df[column], years)\n", | |
" if returns > max_return:\n", | |
" max_return = returns\n", | |
" return max_return\n", | |
"\n", | |
"\n" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 19, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"def rebalance (df, rebalancing_period, increment_period, starting_amount):\n", | |
" \n", | |
" starting_date = df.index[0]\n", | |
" output = {'date': [starting_date], 'value': [starting_amount], 'fees': [0], 'failed transactions':[0], 'successful transactions': [0]}\n", | |
" date = df.index[1]\n", | |
" end_date = df.index[-1]\n", | |
" years = (end_date - starting_date).days / 365\n", | |
" \n", | |
" tickers = df.columns\n", | |
" tick_size = set_min_trading_sizes(tickers, 0.001)\n", | |
" target_allocation = set_initial_allocation(tickers)\n", | |
" \n", | |
" amount = starting_amount\n", | |
" allocation = target_allocation * amount\n", | |
" rebalancing_array = gen_rebalancing_dates(starting_date, end_date, rebalancing_period)\n", | |
" \n", | |
" no_rebalance_end_value = ((df.loc[end_date] / df.loc[date]) * allocation).sum()\n", | |
" drifting_return = (((no_rebalance_end_value / amount)) ** (1/years)) - 1\n", | |
" \n", | |
" while date < end_date:\n", | |
" # if it is a rebalance date\n", | |
" if date in rebalancing_array:\n", | |
" previous_price = df.loc[date - increment_period]\n", | |
" current_price = df.loc[date]\n", | |
" current_alloc = ((current_price / previous_price) * allocation)\n", | |
" new_alloc = current_alloc.sum() * target_allocation\n", | |
" trading_limits_usd = tick_size * df.loc[date]['bitcoin']\n", | |
" alloc_diff = current_alloc - new_alloc\n", | |
" coins_to_sell = alloc_diff[alloc_diff > 0]\n", | |
" coins_to_sell_minus_btc = coins_to_sell[coins_to_sell.index !='bitcoin']\n", | |
" increments_to_sell = coins_to_sell_minus_btc // trading_limits_usd\n", | |
" failed_sells = np.count_nonzero(increments_to_sell < 1 & pd.notna(increments_to_sell))\n", | |
" successful_sells = np.count_nonzero([increments_to_sell > 1])\n", | |
" amounts_to_sell = increments_to_sell * trading_limits_usd\n", | |
" sell_alloc = amounts_to_sell.fillna(0)\n", | |
" intermittent_alloc = current_alloc - sell_alloc\n", | |
" sell_fees = sell_alloc.sum() * 0.001 #fee %\n", | |
" intermittent_alloc['bitcoin'] = intermittent_alloc['bitcoin'] + sell_alloc.sum() - sell_fees\n", | |
" new_alloc_diff = new_alloc - intermittent_alloc \n", | |
" coins_to_buy = new_alloc_diff[new_alloc_diff > 0]\n", | |
" coins_to_buy_no_btc = coins_to_buy[coins_to_buy.index !='bitcoin']\n", | |
" increments_to_buy = coins_to_buy_no_btc // trading_limits_usd\n", | |
" successful_buys = np.count_nonzero([increments_to_buy > 1])\n", | |
" failed_buys = np.count_nonzero([increments_to_buy < 1 & pd.notna(increments_to_buy)])\n", | |
" amounts_to_buy = increments_to_buy * trading_limits_usd\n", | |
" buy_alloc = amounts_to_buy.fillna(0)\n", | |
" buy_fees_alloc = buy_alloc * 0.001 #fee %\n", | |
" final_alloc = intermittent_alloc + buy_alloc - buy_fees_alloc\n", | |
" final_alloc['bitcoin'] = final_alloc['bitcoin'] - buy_alloc.sum()\n", | |
" total_fees = buy_fees_alloc.sum() + sell_fees\n", | |
" allocation = final_alloc\n", | |
" failed_trades = failed_sells + failed_buys \n", | |
" successful_trades = successful_sells + successful_buys\n", | |
" output['fees'].append(total_fees)\n", | |
" output['date'].append(date)\n", | |
" output['value'].append(allocation.sum()) \n", | |
" output['failed transactions'].append(failed_trades)\n", | |
" output['successful transactions'].append(successful_trades)\n", | |
" date += increment_period \n", | |
" # if it is not a rebalance date\n", | |
" else:\n", | |
" previous_price = df.loc[date - increment_period]\n", | |
" current_price = df.loc[date]\n", | |
" allocation = ((current_price / previous_price) * allocation)\n", | |
" amount = allocation.sum()\n", | |
" output['fees'].append(0)\n", | |
" output['date'].append(date)\n", | |
" output['value'].append(amount)\n", | |
" output['failed transactions'].append(0)\n", | |
" output['successful transactions'].append(0)\n", | |
" date += increment_period \n", | |
" \n", | |
" rebalancing_df = pd.DataFrame(output).set_index('date')\n", | |
" max_return_difference = calc_max_return_difference(df, years)\n", | |
" rebalancing_return = annualize_returns(rebalancing_df['value'], years)\n", | |
" total_fees = rebalancing_df['fees'].sum()\n", | |
" failed_trades = rebalancing_df['failed transactions'].sum()\n", | |
" successful_trades = rebalancing_df['successful transactions'].sum()\n", | |
" successful_trade_percentage = successful_trades / (successful_trades + failed_trades)\n", | |
" return {\n", | |
" 'Return Difference': max_return_difference *100,\n", | |
" 'Rebalancing Bonus' : (rebalancing_return *100) - (drifting_return *100),\n", | |
" 'Rebalanced End Value': rebalancing_df['value'][-1] ,\n", | |
" 'Total Fees': total_fees,\n", | |
" 'Successful Trading Percentage': successful_trade_percentage,\n", | |
" 'Tickers': tickers.values,\n", | |
" \n", | |
" }\n", | |
"\n" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 23, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"rebalancing period 1 num_asset 10 simulation 1\n", | |
"rebalancing period 1 num_asset 10 simulation 2\n" | |
] | |
} | |
], | |
"source": [ | |
"evaluate_dict = {'Return Difference': [], 'Rebalancing Bonus': [], 'Rebalanced End Value': [], 'Total Fees': [], 'Successful Trading Percentage': [], 'Rebalancing Period': [], 'Tickers': [] }\n", | |
"rebalancing_periods = []\n", | |
"\n", | |
"# Number of simulations\n", | |
"for simulation in range(1,3):\n", | |
" random_assets = get_n_random_assets(10, df)\n", | |
" for rebalancing_period in range(1,2):\n", | |
" print('rebalancing period', ' ', rebalancing_period, ' num_asset ', 10, 'simulation', ' ', simulation)\n", | |
" result = rebalance(random_assets, pd.Timedelta(days=rebalancing_period), pd.Timedelta(days=1), 1000)\n", | |
" evaluate_dict['Return Difference'].append(result['Return Difference'])\n", | |
" evaluate_dict['Rebalancing Bonus'].append(result['Rebalancing Bonus'])\n", | |
" evaluate_dict['Rebalanced End Value'].append(result['Rebalanced End Value'])\n", | |
" evaluate_dict['Total Fees'].append(result['Total Fees'])\n", | |
" evaluate_dict['Successful Trading Percentage'].append(result['Successful Trading Percentage'])\n", | |
" evaluate_dict['Rebalancing Period'].append(rebalancing_period)\n", | |
" evaluate_dict['Tickers'].append(str(result['Tickers']))\n", | |
"evaluate_df = pd.DataFrame(evaluate_dict)\n" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 13, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/html": [ | |
"<div>\n", | |
"<style scoped>\n", | |
" .dataframe tbody tr th:only-of-type {\n", | |
" vertical-align: middle;\n", | |
" }\n", | |
"\n", | |
" .dataframe tbody tr th {\n", | |
" vertical-align: top;\n", | |
" }\n", | |
"\n", | |
" .dataframe thead th {\n", | |
" text-align: right;\n", | |
" }\n", | |
"</style>\n", | |
"<table border=\"1\" class=\"dataframe\">\n", | |
" <thead>\n", | |
" <tr style=\"text-align: right;\">\n", | |
" <th></th>\n", | |
" <th>Return Difference</th>\n", | |
" <th>Rebalancing Bonus</th>\n", | |
" <th>Rebalanced End Value</th>\n", | |
" <th>Total Fees</th>\n", | |
" <th>Successful Trading Percentage</th>\n", | |
" <th>Rebalancing Period</th>\n", | |
" <th>Tickers</th>\n", | |
" </tr>\n", | |
" </thead>\n", | |
" <tbody>\n", | |
" <tr>\n", | |
" <th>0</th>\n", | |
" <td>31.2643</td>\n", | |
" <td>71.456036</td>\n", | |
" <td>1400.901757</td>\n", | |
" <td>83.169877</td>\n", | |
" <td>0.555422</td>\n", | |
" <td>1</td>\n", | |
" <td>['revain' 'dent' 'aion' 'enigma' 'enjin-coin' ...</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>1</th>\n", | |
" <td>0.0000</td>\n", | |
" <td>13.686982</td>\n", | |
" <td>463.785862</td>\n", | |
" <td>12.038766</td>\n", | |
" <td>0.072878</td>\n", | |
" <td>1</td>\n", | |
" <td>['enigma' 'vertcoin' 'zencash' 'monero' 'qtum'...</td>\n", | |
" </tr>\n", | |
" </tbody>\n", | |
"</table>\n", | |
"</div>" | |
], | |
"text/plain": [ | |
" Return Difference Rebalancing Bonus Rebalanced End Value Total Fees \\\n", | |
"0 31.2643 71.456036 1400.901757 83.169877 \n", | |
"1 0.0000 13.686982 463.785862 12.038766 \n", | |
"\n", | |
" Successful Trading Percentage Rebalancing Period \\\n", | |
"0 0.555422 1 \n", | |
"1 0.072878 1 \n", | |
"\n", | |
" Tickers \n", | |
"0 ['revain' 'dent' 'aion' 'enigma' 'enjin-coin' ... \n", | |
"1 ['enigma' 'vertcoin' 'zencash' 'monero' 'qtum'... " | |
] | |
}, | |
"execution_count": 13, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"evaluate_df" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": { | |
"scrolled": true | |
}, | |
"outputs": [], | |
"source": [] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": { | |
"scrolled": true | |
}, | |
"outputs": [], | |
"source": [] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": {}, | |
"outputs": [], | |
"source": [] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": {}, | |
"outputs": [], | |
"source": [] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": {}, | |
"outputs": [], | |
"source": [] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": {}, | |
"outputs": [], | |
"source": [] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": {}, | |
"outputs": [], | |
"source": [] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": {}, | |
"outputs": [], | |
"source": [] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": {}, | |
"outputs": [], | |
"source": [] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": {}, | |
"outputs": [], | |
"source": [] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": {}, | |
"outputs": [], | |
"source": [] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": {}, | |
"outputs": [], | |
"source": [] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": {}, | |
"outputs": [], | |
"source": [] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": {}, | |
"outputs": [], | |
"source": [] | |
} | |
], | |
"metadata": { | |
"anaconda-cloud": {}, | |
"kernelspec": { | |
"display_name": "Python 3", | |
"language": "python", | |
"name": "python3" | |
}, | |
"language_info": { | |
"codemirror_mode": { | |
"name": "ipython", | |
"version": 3 | |
}, | |
"file_extension": ".py", | |
"mimetype": "text/x-python", | |
"name": "python", | |
"nbconvert_exporter": "python", | |
"pygments_lexer": "ipython3", | |
"version": "3.6.4" | |
} | |
}, | |
"nbformat": 4, | |
"nbformat_minor": 1 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment