Skip to content

Commit

Permalink
Initial upload
Browse files Browse the repository at this point in the history
  • Loading branch information
fingoldo committed May 22, 2023
0 parents commit 7720ebe
Show file tree
Hide file tree
Showing 46 changed files with 24,195 additions and 0 deletions.
138 changes: 138 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit extract_message_update_filters_callback_ngrams_only / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
target/

# Jupyter Notebook
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py

# pyenv
.python-version

# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock

# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/

# Celery stuff
celerybeat-schedule
celerybeat.pid

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/

# JetBrains
.idea/

# Cloud Translation service key
app/cloud_translation_key.json

# Pickle file
app/all_data.pkl
142 changes: 142 additions & 0 deletions Backtesting.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
import pandas as pd
import numpy as np

#@profile
def FullBacktest(base,all_dates,all_spreads,cStartCapital,period_span_in_days,recency,min_periods_before,min_assets_available,backtest_chunk_size,verbose=False):
res=pd.DataFrame(columns=['date','fTotalProfit','fTotalTurnOver','fROI','fTotalComm','lNumBets','fMaxDDPercent','lMaxDDDuration','num_available_assets'])
if verbose:
outcomes=pd.DataFrame(index=np.arange(len(base.index.unique())*len(base['level_spread'].unique())),columns=base.reset_index().columns)
else:
outcomes=None
cntr=0
one_day=np.timedelta64(1, 'D');n_days=np.timedelta64(period_span_in_days * recency, 'D');
for cur_idx in range(min_periods_before+1,len(all_dates)-backtest_chunk_size):
########################################################################################################################################################################################################################################
#Micro-sim inits
########################################################################################################################################################################################################################################
lNumBets = 0;
fTotalComm = 0; fTotalProfit = 0; fTotalTurnOver = 0;
fMaxDDPercent = 0; lMaxDDDuration = 0; lHighestCapitalBetIndex = 0
fCurBalance = cStartCapital; fHighestBlance = fCurBalance; fLowestBlance = fCurBalance
if verbose:
print (str(all_dates[cur_idx])+" weekly chunk started")
for per in range (backtest_chunk_size):
cur_date=all_dates[cur_idx+per]
#print(cur_date)
next_base=base.loc[cur_date]
available_assets = next_base['ticker'].unique()
num_available_assets=len(available_assets)
if num_available_assets>=min_assets_available:
#print("Available assets for that date: "+str(available_assets))
########################################################################################################################################################################################################################################
#Need to select what capital % to use for each of available_assets, and what Spread
########################################################################################################################################################################################################################################

########################################################################################################################################################################################################################################
#1. random selection of Spread at each step, capital gets divided uniformly between all available assets/markets
########################################################################################################################################################################################################################################

#funds_allocated=np.ones(num_available_assets)*cStartCapital/num_available_assets
#spreads_to_use=np.random.choice(all_spreads,num_available_assets,replace=True)

########################################################################################################################################################################################################################################
#2. using at each step of Spread which has on average worked best before:
########################################################################################################################################################################################################################################
# 2.1) for that asset since early days till "now"

hist_perf = base.loc[(cur_date - n_days):(cur_date - one_day)].groupby(['ticker', 'level_spread'])

#hist_perf = base.loc[cur_date].groupby(['ticker', 'level_spread']) #Cheating!

hist_perf_med=hist_perf['perf'].median().reset_index().set_index(['ticker'],inplace=False)
spreads_to_use=[]

best_historical_perfs_by_asset=[]
for next_asset in range(num_available_assets):
fSpreadToUse=0;cur_best_perf=0
if available_assets[next_asset] in hist_perf_med.index:
possible_spreads_to_use=hist_perf_med.loc[available_assets[next_asset]]
if possible_spreads_to_use.size>0:
perfs=possible_spreads_to_use['perf'].values
the_ind = np.argmax(perfs)
best_historical_perf=perfs[the_ind]
if best_historical_perf>0:
best_spread_to_use=possible_spreads_to_use.iloc[[the_ind]]
cur_best_perf=best_spread_to_use['perf'].iloc[0] #!!!
if verbose:
print("Spread chosen for " + str(available_assets[next_asset]) + ":")
display(best_spread_to_use)
print("Its expected performance: "+str(best_spread_to_use['perf']))
fSpreadToUse=best_spread_to_use['level_spread'].iloc[0]
best_historical_perfs_by_asset.append(cur_best_perf) #!!!
spreads_to_use.append(fSpreadToUse)

funds_allocated=np.ones(num_available_assets)*cStartCapital/num_available_assets
#print(best_historical_perfs_by_asset)
avg_perf=np.median(best_historical_perfs_by_asset)
funds_allocated[best_historical_perfs_by_asset>avg_perf]+=cStartCapital/num_available_assets/2
funds_allocated[best_historical_perfs_by_asset<avg_perf]-=cStartCapital/num_available_assets/2
#print (np.sum(funds_allocated))

if verbose:
print("funds_allocated:"+str(funds_allocated))
print("spreads_to_use:"+str(spreads_to_use))

########################################################################################################################################################################################################################################
#Capital calculation at the end of this week
########################################################################################################################################################################################################################################
fProfit=0;fComm=0;fTurnover=0;prev_spread=0;
for next_asset in range(num_available_assets):
funds=funds_allocated[next_asset]
if ((funds>0) & (spreads_to_use[next_asset]>0)):

########################################################################################################################################################################################################################################
#next_sim=next_base[(next_base['ticker'] ==available_assets[next_asset]) & (next_base['level_spread'] == spreads_to_use[next_asset])]

c_t=np.where(next_base['ticker'].values == available_assets[next_asset])
if prev_spread!=spreads_to_use[next_asset]:
c_l=np.where(next_base['level_spread'].values == spreads_to_use[next_asset])
prev_spread=spreads_to_use[next_asset]
next_sim=next_base.iloc[np.intersect1d(c_t,c_l)]
########################################################################################################################################################################################################################################

pr=next_sim['total_profit'].iloc[0]
if pr<2:
if verbose:
outcomes.iloc[cntr]=next_sim.reset_index().iloc[0]
cntr+=1

fComm+=next_sim['total_commission'].iloc[0]*funds
lNumBets+=next_sim['num_bets'].iloc[0]
roi=next_sim['roi'].iloc[0]
fProfit+=pr*funds
if roi!=0:
fTurnover+=pr/roi*funds

fTotalComm+=fComm
fCurBalance+=fProfit
fTotalProfit+=fProfit
fTotalTurnOver+=fTurnover

if (fCurBalance > fHighestBlance) | (per==(backtest_chunk_size-1)):
fCurDD = (fHighestBlance - fLowestBlance) / fHighestBlance
if fCurDD > fMaxDDPercent:
fMaxDDPercent = fCurDD
lCurDDDuration = per - lHighestCapitalBetIndex
if lCurDDDuration > lMaxDDDuration:
lMaxDDDuration = lCurDDDuration

lHighestCapitalBetIndex = per

fHighestBlance = fCurBalance; fLowestBlance = fCurBalance
else:
if fCurBalance < fLowestBlance:
fLowestBlance = fCurBalance
if fTotalTurnOver>0:
fROI=fTotalProfit/fTotalTurnOver
res.loc[len(res)] = [all_dates[cur_idx],fTotalProfit,fTotalTurnOver,fROI,fTotalComm,lNumBets,fMaxDDPercent,lMaxDDDuration,num_available_assets]
if verbose:
print ('Weekly results: fTotalProfit='+str(fTotalProfit)+',fMaxDDPercent='+str(fMaxDDPercent)+',lNumBets='+str(lNumBets)+',fROI='+str(fROI)+',assets: '+str(num_available_assets))
if cntr>1000:
return res,outcomes
return res,outcomes
36 changes: 36 additions & 0 deletions Data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@

########################################################################################################################################################################################################################################
# Load data
########################################################################################################################################################################################################################################
import pandas as pd


# Load data from csv
def LoadDataFromCsv(sHistoricalDataPath, sTicker, lTimeFrameInMinutes):
ds = pd.read_csv(
open(sHistoricalDataPath + sTicker + '_' + str(lTimeFrameInMinutes) + '_2010-01-01_2017-07-01', 'r'));
del ds[ds.columns[0]];
ds['date'] = ds['date'].astype('datetime64[ns]');
return ds


# Download different timeframes and currency pairs from Poloniex website and save them on the disk as csv format

def DownloadCurrencyPairCandlesPoloniex(dtFrom, dtTo, sCurrencyPair, lPeriod):
tmp_pd = pd.read_json(
'https://poloniex.com/public?command=returnChartData&currencyPair=' + sCurrencyPair + '&start=' + str(
int(time.mktime(dtFrom.timetuple()))) + '&end=' + str(
int(time.mktime(dtTo.timetuple()))) + '&period=' + str(lPeriod));
tmp_pd.to_csv('CryptoCurrency\\history\\candles\poloniex\\' + sCurrencyPair + '_' + str(lPeriod) + '_' + str(
dtFrom) + '_' + str(dtTo))


def DownloadAllPoloniexCandles():
pdTickers = pd.read_json('https://poloniex.com/public?command=returnTicker');
for NextTicker in pdTickers.columns:
print(NextTicker)
if (NextTicker > 'BTC_FLDC'):
for lPeriod in [300, 900, 1800, 7200, 14400, 86400]:
print('\t ' + str(lPeriod))
DownloadCurrencyPairCandlesPoloniex(datetime.date(2010, 1, 1), datetime.date(2017, 7, 1), NextTicker,
lPeriod)
Loading

0 comments on commit 7720ebe

Please sign in to comment.