plotguy 2.1.7__tar.gz → 2.1.9__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {plotguy-2.1.7 → plotguy-2.1.9}/PKG-INFO +1 -1
- {plotguy-2.1.7 → plotguy-2.1.9}/plotguy/__init__.py +56 -18
- {plotguy-2.1.7 → plotguy-2.1.9}/plotguy/components.py +68 -68
- {plotguy-2.1.7 → plotguy-2.1.9}/plotguy.egg-info/PKG-INFO +1 -1
- {plotguy-2.1.7 → plotguy-2.1.9}/setup.py +1 -1
- {plotguy-2.1.7 → plotguy-2.1.9}/README.md +0 -0
- {plotguy-2.1.7 → plotguy-2.1.9}/plotguy/aggregate.py +0 -0
- {plotguy-2.1.7 → plotguy-2.1.9}/plotguy/equity_curves.py +0 -0
- {plotguy-2.1.7 → plotguy-2.1.9}/plotguy/signals.py +0 -0
- {plotguy-2.1.7 → plotguy-2.1.9}/plotguy.egg-info/SOURCES.txt +0 -0
- {plotguy-2.1.7 → plotguy-2.1.9}/plotguy.egg-info/dependency_links.txt +0 -0
- {plotguy-2.1.7 → plotguy-2.1.9}/plotguy.egg-info/requires.txt +0 -0
- {plotguy-2.1.7 → plotguy-2.1.9}/plotguy.egg-info/top_level.txt +0 -0
- {plotguy-2.1.7 → plotguy-2.1.9}/setup.cfg +0 -0
|
@@ -11,14 +11,16 @@ import zlib
|
|
|
11
11
|
import requests
|
|
12
12
|
import pandas as pd
|
|
13
13
|
import numpy as np
|
|
14
|
+
import io
|
|
14
15
|
|
|
15
16
|
from .equity_curves import *
|
|
16
17
|
from .signals import *
|
|
17
18
|
from .aggregate import *
|
|
18
19
|
from .components import *
|
|
19
20
|
import itertools
|
|
21
|
+
from bs4 import BeautifulSoup
|
|
20
22
|
|
|
21
|
-
def get_all_para_combination(para_dict, backtest_attribute, df_dict, sec_profile, manager_list):
|
|
23
|
+
def get_all_para_combination(para_dict, backtest_attribute, df_dict, sec_profile, manager_list, count_down=False):
|
|
22
24
|
|
|
23
25
|
risk_free_rate = get_risk_free_rate(backtest_attribute['start_date'], backtest_attribute['end_date'])
|
|
24
26
|
|
|
@@ -60,11 +62,12 @@ def get_all_para_combination(para_dict, backtest_attribute, df_dict, sec_profile
|
|
|
60
62
|
|
|
61
63
|
all_para_combination[ref_code] = para_combination
|
|
62
64
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
65
|
+
if count_down:
|
|
66
|
+
print('5 second countdown before running backtest()')
|
|
67
|
+
for i in range(5):
|
|
68
|
+
print(5 - i)
|
|
69
|
+
time.sleep(1)
|
|
70
|
+
print(0)
|
|
68
71
|
|
|
69
72
|
print(datetime.datetime.now().strftime('%H:%M:%S'), 'start running backtest()')
|
|
70
73
|
|
|
@@ -75,8 +78,6 @@ def generate_or_read_backtest_result(read_only, mp_mode, number_of_core, manager
|
|
|
75
78
|
|
|
76
79
|
if read_only and os.path.isfile('backtest_result.parquet'):
|
|
77
80
|
backtest_result_df = pd.read_parquet('backtest_result.parquet')
|
|
78
|
-
#backtest_result_df = backtest_result_df[backtest_result_df.index.isin(all_para_combination.keys())]
|
|
79
|
-
|
|
80
81
|
else:
|
|
81
82
|
t1 = datetime.datetime.now()
|
|
82
83
|
if mp_mode:
|
|
@@ -117,6 +118,7 @@ def save_backtest_result(df, para_combination_item):
|
|
|
117
118
|
risk_free_rate = para_combination['risk_free_rate']
|
|
118
119
|
default_market_price = para_combination['default_market_price']
|
|
119
120
|
intraday = para_combination['intraday']
|
|
121
|
+
long_short = para_combination['long_short']
|
|
120
122
|
|
|
121
123
|
total_commission = df['commission'].sum()
|
|
122
124
|
|
|
@@ -149,10 +151,10 @@ def save_backtest_result(df, para_combination_item):
|
|
|
149
151
|
|
|
150
152
|
price_return_on_capital = price_net_profit / df_daily.at[df_daily.index[0], 'price']
|
|
151
153
|
price_annualized_return = (np.sign(1 + price_return_on_capital) * np.abs(1 + price_return_on_capital)) ** (
|
|
152
|
-
|
|
154
|
+
365 / holding_period_day) - 1
|
|
153
155
|
price_annualized_std = price_pct_series.std() * math.sqrt(365)
|
|
154
156
|
price_annualized_sr = (
|
|
155
|
-
|
|
157
|
+
price_annualized_return - risk_free_rate / 100) / price_annualized_std if price_annualized_std != 0 else 0
|
|
156
158
|
price_net_profit_to_mdd = price_net_profit / price_mdd_dollar if price_mdd_dollar != 0 else 0
|
|
157
159
|
|
|
158
160
|
price_return_on_capital = round(100 * price_return_on_capital, 2)
|
|
@@ -215,7 +217,7 @@ def save_backtest_result(df, para_combination_item):
|
|
|
215
217
|
yearly_stats['year_return'] = 100 * (yearly_stats['year_pnl'] / yearly_stats['year_start_equity_value'])
|
|
216
218
|
yearly_stats['year_win_rate'] = 100 * (yearly_stats['year_win_count'] / yearly_stats['year_trade_count'])
|
|
217
219
|
|
|
218
|
-
cov_return = yearly_stats['
|
|
220
|
+
cov_return = yearly_stats['year_return'].std() / yearly_stats['year_return'].mean() if yearly_stats['year_return'].mean() != 0 else 0
|
|
219
221
|
cov_count = yearly_stats['year_trade_count'].std() / yearly_stats['year_trade_count'].mean() if yearly_stats['year_trade_count'].mean() != 0 else 0
|
|
220
222
|
|
|
221
223
|
yearly_stats = yearly_stats.applymap(lambda x: f'{x:.2f}')
|
|
@@ -257,10 +259,10 @@ def save_backtest_result(df, para_combination_item):
|
|
|
257
259
|
|
|
258
260
|
equity_return_on_capital = equity_net_profit / df.at[df.index[0], 'equity_value']
|
|
259
261
|
equity_annualized_return = (np.sign(1 + equity_return_on_capital) * np.abs(1 + equity_return_on_capital)) ** (
|
|
260
|
-
|
|
262
|
+
365 / holding_period_day) - 1
|
|
261
263
|
equity_annualized_std = equity_pct_series.std() * math.sqrt(365)
|
|
262
264
|
equity_annualized_sr = (
|
|
263
|
-
|
|
265
|
+
equity_annualized_return - risk_free_rate / 100) / equity_annualized_std if equity_annualized_std != 0 else 0
|
|
264
266
|
equity_net_profit_to_mdd = equity_net_profit / equity_mdd_dollar if equity_mdd_dollar != 0 else 0
|
|
265
267
|
|
|
266
268
|
equity_return_on_capital = round(100 * equity_return_on_capital, 2)
|
|
@@ -269,7 +271,11 @@ def save_backtest_result(df, para_combination_item):
|
|
|
269
271
|
equity_annualized_sr = round(equity_annualized_sr, 2)
|
|
270
272
|
equity_net_profit_to_mdd = round(100 * equity_net_profit_to_mdd, 2)
|
|
271
273
|
|
|
272
|
-
|
|
274
|
+
if long_short == 'short':
|
|
275
|
+
return_on_capital_diff = equity_annualized_return - (-1) * price_annualized_return
|
|
276
|
+
else:
|
|
277
|
+
### consider both long and long_short ###
|
|
278
|
+
return_on_capital_diff = equity_annualized_return - price_annualized_return
|
|
273
279
|
|
|
274
280
|
if intraday:
|
|
275
281
|
df = df[['price', 'equity_value']]
|
|
@@ -343,8 +349,11 @@ def get_risk_free_rate(start_date, end_date):
|
|
|
343
349
|
else:
|
|
344
350
|
risk_free_rate = get_geometric_mean_of_yearly_rate(start_date_year, end_date_year)
|
|
345
351
|
except:
|
|
346
|
-
|
|
347
|
-
|
|
352
|
+
try:
|
|
353
|
+
risk_free_rate = get_geometric_mean_of_yearly_rate_backup(start_date_year, end_date_year)
|
|
354
|
+
except:
|
|
355
|
+
risk_free_rate = 2 # if network error, set rate to 2 %
|
|
356
|
+
print('Network error. Risk free rate: {:.2f} %'.format(risk_free_rate))
|
|
348
357
|
|
|
349
358
|
return risk_free_rate
|
|
350
359
|
|
|
@@ -379,9 +388,9 @@ def get_latest_fed_fund_rate():
|
|
|
379
388
|
return fed_funds_rate
|
|
380
389
|
|
|
381
390
|
|
|
382
|
-
def get_geometric_mean_of_yearly_rate(start_year, end_year):
|
|
391
|
+
def get_geometric_mean_of_yearly_rate(start_year, end_year):
|
|
383
392
|
url = "https://fred.stlouisfed.org/graph/fredgraph.csv?id=DTB3"
|
|
384
|
-
response = requests.get(url)
|
|
393
|
+
response = requests.get(url, timeout=10)
|
|
385
394
|
data = response.text.split("\n")[:-1]
|
|
386
395
|
data = [row.split(",") for row in data]
|
|
387
396
|
df = pd.DataFrame(data[1:], columns=data[0])
|
|
@@ -389,6 +398,35 @@ def get_geometric_mean_of_yearly_rate(start_year, end_year): # backtest period
|
|
|
389
398
|
df["date"] = pd.to_datetime(df["date"])
|
|
390
399
|
df["risk_free_rate"] = pd.to_numeric(df["risk_free_rate"], errors='coerce')
|
|
391
400
|
df.dropna(subset=['risk_free_rate'], inplace=True)
|
|
401
|
+
print('Got Federal Funds Rate from stlouisfed.org')
|
|
402
|
+
|
|
403
|
+
risk_free_rate_history_yearly = df.resample("A", on="date").mean()
|
|
404
|
+
risk_free_rate_history_yearly = risk_free_rate_history_yearly.round(3)
|
|
405
|
+
|
|
406
|
+
# show only start between start_year and end_year
|
|
407
|
+
risk_free_rate_history_yearly = risk_free_rate_history_yearly[
|
|
408
|
+
risk_free_rate_history_yearly.index.year >= start_year]
|
|
409
|
+
risk_free_rate_history_yearly = risk_free_rate_history_yearly[risk_free_rate_history_yearly.index.year <= end_year]
|
|
410
|
+
|
|
411
|
+
fed_fund_rate_geometric_mean = np.exp(np.log(risk_free_rate_history_yearly["risk_free_rate"]).mean())
|
|
412
|
+
fed_fund_rate_geometric_mean = round(fed_fund_rate_geometric_mean, 2)
|
|
413
|
+
print("Federal Funds Rate Geometric mean from {} to {}: {} %".format(start_year, end_year,
|
|
414
|
+
fed_fund_rate_geometric_mean))
|
|
415
|
+
|
|
416
|
+
return fed_fund_rate_geometric_mean
|
|
417
|
+
|
|
418
|
+
def get_geometric_mean_of_yearly_rate_backup(start_year, end_year):
|
|
419
|
+
url = '/get_fred'
|
|
420
|
+
my_headers = {'token': '3f52e8c4-8c49-4c9a-8c57-1e4e9f6b0a40'}
|
|
421
|
+
my_main_url = "http://120.26.40.125:8080"
|
|
422
|
+
response = requests.get(f'{my_main_url}{url}', headers=my_headers)
|
|
423
|
+
data_str = response.content.decode('utf-8')
|
|
424
|
+
data_io = io.StringIO(data_str)
|
|
425
|
+
df = pd.read_csv(data_io)
|
|
426
|
+
df = df.rename(columns={'value' : 'risk_free_rate'})
|
|
427
|
+
df["date"] = pd.to_datetime(df["date"])
|
|
428
|
+
df.dropna(subset=['risk_free_rate'], inplace=True)
|
|
429
|
+
print('Got Federal Funds Rate from backup source')
|
|
392
430
|
|
|
393
431
|
risk_free_rate_history_yearly = df.resample("A", on="date").mean()
|
|
394
432
|
risk_free_rate_history_yearly = risk_free_rate_history_yearly.round(3)
|
|
@@ -316,7 +316,7 @@ class Components:
|
|
|
316
316
|
result_df['equity_annualized_std'] = result_df['equity_annualized_std'].apply(lambda x: f"{x:,.2f} %")
|
|
317
317
|
result_df['equity_annualized_sr'] = result_df['equity_annualized_sr'].apply(lambda x: f"{x:,.2f}")
|
|
318
318
|
|
|
319
|
-
result_df['return_on_capital_diff'] = result_df['return_on_capital_diff'].apply(lambda x: f"{x:,.0f}")
|
|
319
|
+
result_df['return_on_capital_diff'] = result_df['return_on_capital_diff'].apply(lambda x: f"{x:,.0f} %")
|
|
320
320
|
|
|
321
321
|
result_df['price_mdd_dollar'] = result_df['price_mdd_dollar'].apply(lambda x: f"{int(x):,}")
|
|
322
322
|
result_df['price_mdd_pct'] = result_df['price_mdd_pct'].apply(lambda x: f"{x:,.2f} %")
|
|
@@ -798,73 +798,73 @@ class Components:
|
|
|
798
798
|
saved_strategies_path = os.path.join(str_dir, 'saved_strategies.parquet')
|
|
799
799
|
saved_strategies_df = pd.read_parquet(saved_strategies_path)
|
|
800
800
|
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
801
|
+
for i, row in saved_strategies_df.iterrows():
|
|
802
|
+
equity_path = os.path.join(str_dir, row["equity_curve_folder"], str(row['ref_code']) + '.parquet')
|
|
803
|
+
#df_equity = pd.read_parquet(equity_path)
|
|
804
|
+
|
|
805
|
+
yearly_stats_string = row['yearly_stats_string']
|
|
806
|
+
para_keys_str = row['para_keys_str']
|
|
807
|
+
para_keys_list = para_keys_str.split('|')
|
|
808
|
+
|
|
809
|
+
parameters = {}
|
|
810
|
+
for para_keys in para_keys_list:
|
|
811
|
+
parameters[para_keys] = str(row[para_keys])
|
|
812
|
+
|
|
813
|
+
equity_curve_dict = {}
|
|
814
|
+
|
|
815
|
+
equity_curve_dict['folder'] = str_dir
|
|
816
|
+
equity_curve_dict['backtest_name'] = row['backtest_name']
|
|
817
|
+
equity_curve_dict['equity_path'] = equity_path
|
|
818
|
+
equity_curve_dict['parameters'] = parameters
|
|
819
|
+
|
|
820
|
+
equity_curve_dict['performance'] = {
|
|
821
|
+
'initial_capital': row['initial_capital'],
|
|
822
|
+
'sharpe_ratio': row['equity_annualized_sr'],
|
|
823
|
+
'annualized_return': row['equity_annualized_return'],
|
|
824
|
+
'net_profit_to_mdd': row['equity_net_profit_to_mdd'],
|
|
825
|
+
'net_profit': row['equity_net_profit'],
|
|
826
|
+
'mdd_dollar': row['equity_mdd_dollar'],
|
|
827
|
+
'mdd_pct': row['equity_mdd_pct'],
|
|
828
|
+
'num_of_trade': row['num_of_trade'],
|
|
829
|
+
'num_of_win': row['num_of_win'],
|
|
830
|
+
'return_on_capital': row['equity_return_on_capital'],
|
|
831
|
+
'total_commission': row['total_commission'],
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
ref_code = str(row['ref_code'])
|
|
835
|
+
equity_curve_dict['ref_code'] = ref_code
|
|
836
|
+
|
|
837
|
+
yearly_stats_dict = {}
|
|
838
|
+
years_data = yearly_stats_string.split("|")
|
|
839
|
+
|
|
840
|
+
for year_data in years_data:
|
|
841
|
+
parts = year_data.split(",")
|
|
842
|
+
year = parts[0]
|
|
843
|
+
yearly_stats_dict[year] = {}
|
|
844
|
+
|
|
845
|
+
for item in parts[1:]:
|
|
846
|
+
key, value = item.split(":")
|
|
847
|
+
yearly_stats_dict[year][key] = float(value)
|
|
848
|
+
|
|
849
|
+
for idx, (year, value) in enumerate(yearly_stats_dict.items()):
|
|
850
|
+
year_trade_count = value['year_trade_count']
|
|
851
|
+
year_win_rate = value['year_win_rate']
|
|
852
|
+
year_return = value['year_return']
|
|
853
|
+
|
|
854
|
+
year_win_count = year_trade_count * year_win_rate * 0.01
|
|
855
|
+
|
|
856
|
+
### dont remove ###
|
|
857
|
+
# year_trade_count = "{:d}".format(int(year_trade_count))
|
|
858
|
+
# year_win_count = "{:d}".format(int(year_win_count))
|
|
859
|
+
# year_win_rate = "{:d}%".format(int(year_win_rate))
|
|
860
|
+
# year_return = "{:.2f} %".format(int(year_return))
|
|
861
|
+
|
|
862
|
+
equity_curve_dict['performance'][f'{year} Count'] = year_trade_count
|
|
863
|
+
equity_curve_dict['performance'][f'{year} Win Rate'] = year_win_rate
|
|
864
|
+
equity_curve_dict['performance'][f'{year} Win Count'] = year_win_count
|
|
865
|
+
equity_curve_dict['performance'][f'{year} Return'] = year_return
|
|
866
|
+
|
|
867
|
+
equity_curves_dict_list.append(equity_curve_dict)
|
|
868
868
|
|
|
869
869
|
line_colour = []
|
|
870
870
|
for c in range(len(equity_curves_dict_list)):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|