Search…
Performance analytics
This section showcases how performance reports for strategies can be displayed and customised.
A notebook containing all the code used in this page can be accessed in the research environment: Example notebooks.

Environment

Setting up your environment takes three steps:
  • Import the relevant internal and external libraries
  • Configure the environment parameters
  • Initialise the environment
1
import sigtech.framework as sig
2
from sigtech.framework.analytics.performance.performance_report \
3
import PerformanceReport, View, CustomView
4
5
import uuid
6
import datetime as dtm
7
import pandas as pd
8
import numpy as np
9
import seaborn as sns
10
11
sns.set(rc={'figure.figsize': (18, 6)})
12
13
if not sig.config.is_initialised():
14
date = dtm.datetime(2020, 10, 30)
15
sig.config.init(data_date=date, env_date=date)
16
sig.config.set(sig.config.HISTORY_DATA_FILL_MISSING, True)
Copied!

Create a basket of strategies

This step creates sample strategies for the performance report:
1
from sigtech.framework.default_strategy_objects.rolling_futures import *
2
from sigtech.framework.default_strategy_objects.rolling_futures_fx_hedged import *
3
4
us_basket = sig.BasketStrategy(
5
currency='USD',
6
start_date=dtm.date(2017, 1, 4),
7
end_date=dtm.date(2020, 1, 4),
8
constituent_names=[
9
es_index_front().name,
10
ty_comdty_front().name,
11
],
12
weights=[0.5, 0.5],
13
rebalance_frequency='EOM',
14
ticker='USD USA BASKET {}'.format(str(uuid.uuid4())[:8]),
15
)
16
17
ge_basket = sig.BasketStrategy(
18
currency='USD',
19
start_date=dtm.date(2017, 1, 4),
20
end_date=dtm.date(2020, 1, 4),
21
constituent_names=[
22
usd_gx_index_front().name,
23
usd_rx_comdty_front().name,
24
],
25
weights=[0.6, 0.4],
26
rebalance_frequency='EOM',
27
ticker='USD GERMANY BASKET {}'.format(str(uuid.uuid4())[:8]),
28
)
29
30
jp_basket = sig.BasketStrategy(
31
currency='USD',
32
start_date=dtm.date(2017, 1, 4),
33
end_date=dtm.date(2020, 1, 4),
34
constituent_names=[
35
usd_nk_index_front().name,
36
usd_jb_comdty_front().name,
37
],
38
weights=[0.3, 0.7],
39
rebalance_frequency='EOM',
40
ticker='USD JAPAN BASKET {}'.format(str(uuid.uuid4())[:8]),
41
)
42
43
strategy1 = sig.BasketStrategy(
44
currency='USD',
45
start_date=dtm.date(2017, 1, 4),
46
end_date=dtm.date(2020, 1, 4),
47
constituent_names=[us_basket.name, ge_basket.name, jp_basket.name],
48
weights=[0.6, 0.2, 0.2],
49
rebalance_frequency='EOM',
50
ticker='USD WORLD TOP_LEVEL BASKET {}'.format(str(uuid.uuid4())[:8])
51
)
52
53
strategy2 = sig.BasketStrategy(
54
currency='USD',
55
start_date=dtm.date(2017, 1, 4),
56
end_date=dtm.date(2020, 1, 4),
57
constituent_names=[ge_basket.name, jp_basket.name],
58
weights=[0.7, 0.3],
59
rebalance_frequency='EOM',
60
ticker='USD WORLD TOP_LEVEL BASKET {}'.format(str(uuid.uuid4())[:8])
61
)
62
63
strategy3 = sig.BasketStrategy(
64
currency='USD',
65
start_date=dtm.date(2017, 1, 4),
66
end_date=dtm.date(2020, 1, 4),
67
constituent_names=[ge_basket.name, jp_basket.name],
68
weights=[0.9, 0.1],
69
rebalance_frequency='EOM',
70
ticker='USD WORLD TOP_LEVEL BASKET {}'.format(str(uuid.uuid4())[:8])
71
)
Copied!

Create a PerformanceReport from time series

A PerformanceReport can be created for a time series object. Method default_views() shows the report views enabled by default for this object:
Python
Output
1
report0 = PerformanceReport(strategy1.history())
2
report0.default_views()
Copied!
1
[View('SUMMARY_SINGLE'),
2
View('HISTORY'),
3
View('PRESENTATION_PERF_TABLE'),
4
View('SUMMARY_ROLLING_SERIES'),
5
View('ROLLING_RISK_VOL'),
6
View('ROLLING_RISK_SHARPE'),
7
View('ROLLING_PLOTS'),
8
View('MONTHLY_STATS'),
9
View('MONTHLY_STATS_HEATMAP'),
10
View('BENCHMARK_TABLE')]
Copied!

Create a PerformanceReport from strategy

A PerformanceReport can also be created for a Strategy object. Method default_views() shows an extended list of report views enabled by default:
Input
Output
1
report1 = PerformanceReport(strategy1)
2
report1.default_views()
Copied!
1
[View('SUMMARY_SINGLE'),
2
View('HISTORY'),
3
View('PRESENTATION_PERF_TABLE'),
4
View('SUMMARY_ROLLING_SERIES'),
5
View('ROLLING_RISK_VOL'),
6
View('ROLLING_RISK_SHARPE'),
7
View('POSITIONS_DF'),
8
View('TURNOVER'),
9
View('TURNOVER_STATS'),
10
View('ROLLING_PLOTS'),
11
View('MONTHLY_STATS'),
12
View('MONTHLY_STATS_HEATMAP'),
13
View('BENCHMARK_TABLE')]
Copied!

Views

All built-in views can be accessed using the following syntax:
Input
Output
1
View.TURNOVER
Copied!
1
View('TURNOVER')
Copied!
Customised views can be accessed using the following syntax:
Input
Output
1
View('Custom View')
Copied!
1
View('Custom View')
Copied!

Display a report

Method report() will display the views enabled for the object used. Parameter dates can be specified to reduce the output size for tables showing daily data.
Input
Output
1
few_dates = pd.date_range(dtm.date(2019, 12, 2),
2
dtm.date(2020, 1, 1), freq='7d')
3
4
report1 = PerformanceReport(strategy1, name='My Strategy', dates=few_dates)
5
report1.report()
Copied!

Specifying views when initialising PerformanceReport

Parameter views can be used to select a subset of the default views to display:
Input
Output
1
report2 = PerformanceReport(strategy1,
2
name='My Strategy',
3
views=[View.MONTHLY_STATS,
4
View.PRESENTATION_PERF_TABLE],
5
dates=few_dates)
6
report2.views()
Copied!
1
[View('MONTHLY_STATS'), View('PRESENTATION_PERF_TABLE')]
Copied!
Input
Output
1
report2.report()
Copied!

Use of arrange_views()

Within the same report, the order of views can also be re-arranged:
Input
Output
1
report2.arrange_views([View.HISTORY, View.MONTHLY_STATS])
2
report2.report()
Copied!

Add a benchmark strategy or time series

Parameter benchmark can be used to add a strategy or time series to the performance report. The following example uses one strategy as input object:
Input
Output
1
s = es_index_front()
2
b = z_index_front()
3
4
report3 = PerformanceReport(s,
5
benchmark=b,
6
views=[View.POSITIONS_DF, View.TURNOVER_STATS],
7
dates=few_dates)
8
report3.report()
Copied!
The same syntax is available for time series:
Input
Output
1
ts = s.history().rename('ES Rolling Future').loc[
2
dtm.date(2015, 1, 1):dtm.date(2020, 1, 1)]
3
ts_b = b.history()
4
5
report3 = PerformanceReport(ts,
6
benchmark=ts_b,
7
views=[View.HISTORY, View.MONTHLY_STATS,
8
View.BENCHMARK_TABLE])
9
report3.report()
Copied!

Add customised views

Customised views can be added to PerformanceReport by simply defining a new function. The following example defines two functions handling a DataFrame and a Pyplot graph:
1
# Define custom functions for view
2
def custom_table(args):
3
# This function expects 2 parameters (Strategy, Integer)
4
print('Customising for: ', args[0].name)
5
df = pd.DataFrame(np.random.randint(0, args[1], size=(4, 4)),
6
columns=list('ABCD'))
7
return df
8
9
10
def custom_plot(args):
11
# This function expects 1 parameter (PerformanceReport)
12
import matplotlib.pyplot as plt
13
args.rolling_stat('excess_return').plot(
14
title="Rolling excess return", figsize=[15, 4])
15
plt.show()
16
return
Copied!
A CustomView object helps wrapping the customised view and its parameters:
1
custom_view1 = CustomView(custom_table, params=[strategy1, 99],
2
name='Custom Table 99')
3
custom_view2 = CustomView(custom_table, params=[strategy1, 25],
4
name='Custom Table 25')
5
custom_view3 = CustomView(custom_plot, params=report3,
6
name='Custom Plot')
Copied!
The customised views can now be added to the report:
Input
Output
1
report3 = PerformanceReport(strategy1, name='Customised Strategy',
2
views=[View.SUMMARY_SINGLE])
3
report3.add_view(custom_view1)
4
report3.add_views([custom_view2, custom_view3])
5
report3.views()
Copied!
1
[View('SUMMARY_SINGLE'),
2
View('Custom Table 99'),
3
View('Custom Table 25'),
4
View('Custom Plot')]
Copied!
Input
Output
1
report3.report()
Copied!

Support for multiple strategies

Reports for multiple strategies can be visualised by adding them to a list:
Input
Output
1
report1 = PerformanceReport([strategy1, strategy2],
2
benchmark=b, name=['S1', 'S2'],
3
views=[View.SUMMARY_SINGLE, View.HISTORY,
4
View.TURNOVER_STATS, View.BENCHMARK_TABLE])
5
report1.report()
Copied!

Support for multiple time series

Time series can be merged within a DataFrame object:
Input
Output
1
ts1 = es_index_front().history().rename('ES Rolling Future').loc[
2
dtm.date(2015, 1, 1):dtm.date(2020, 1, 1)]
3
ts2 = eo_index_front().history().rename('EO Rolling Future').loc[
4
dtm.date(2015, 1, 1):dtm.date(2020, 1, 1)]
5
b = z_index_front().history()
6
7
ts_df = pd.concat({
8
'ES Rolling Future': ts1,
9
'EO Rolling Future': ts2,
10
}, axis=1)
11
12
rep = PerformanceReport(ts_df, benchmark=b,
13
views=[View.ROLLING_PLOTS, View.BENCHMARK_TABLE])
14
rep.report()
Copied!

Additional parameters for Performance Analytics

You can include currency based metrics in PerformanceReport. The following code block demonstrates how to include these views.
You can include currency based metrics in PerformanceReport. The following code block demonstrates how to include these views:
1
rfs = sig.RollingFutureStrategy(
2
currency='USD',
3
start_date=dtm.date(2020,1,1),
4
contract_code='ES',
5
contract_sector='INDEX',
6
rolling_rule='front',
7
fixed_contracts=1
8
)
9
rfs.build()
10
11
dates = pd.date_range('2021-01-04', '2021-12-01', freq='1W-MON')
12
13
sig.PerformanceReport(rfs, views=[sig.View.SUMMARY_SINGLE_CCY, sig.View.SUMMARY_ROLLING_CCY_SERIES], dates=dates).report()
Copied!
1
rfs = sig.RollingFutureStrategy(
2
currency='USD',
3
start_date=dtm.date(2020,1,1),
4
contract_code='ES',
5
contract_sector='INDEX',
6
rolling_rule='front',
7
fixed_contracts=1
8
)
9
rfs.build()
10
dates = pd.date_range('2021-01-04', '2021-12-01', freq='1W-MON')
11
sig.PerformanceReport(rfs, views=[sig.View.SUMMARY_SINGLE_CCY, sig.View.SUMMARY_ROLLING_CCY_SERIES], dates=dates).report()
Copied!
The aum argument allows you to pass a representative AUM figure. This is useful in strategies where initial_cash=0 as it avoids dividing by zero. Following on from the above code block, the use of this new argument is demonstrated below.
The aum argument allows you to pass a representative AUM figure. This is useful in strategies where initial_cash=0 as it avoids dividing by zero. The use of this argument is demonstrated in the following code block:
1
sig.PerformanceReport(rfs, dates=dates, views=[sig.View.SUMMARY_SINGLE]).report()
2
3
first_contract = sig.obj.get(rfs.rolling_table.rolled_in_contract.iloc[0])
4
first_contract_value = first_contract.history().asof(rfs.start_date.strftime("%Y-%m-%d")) * first_contract.contract_size
5
6
sig.PerformanceReport(
7
rfs,
8
dates=dates,
9
views=[sig.View.SUMMARY_SINGLE],
10
aum=first_contract_value
11
).report()
Copied!
1
sig.PerformanceReport(rfs, dates=dates, views=[sig.View.SUMMARY_SINGLE]).report()
2
first_contract = sig.obj.get(rfs.rolling_table.rolled_in_contract.iloc[0])
3
first_contract_value = first_contract.history().asof(rfs.start_date.strftime("%Y-%m-%d")) * first_contract.contract_size
4
sig.PerformanceReport(
5
rfs,
6
dates=dates,
7
views=[sig.View.SUMMARY_SINGLE],
8
aum=first_contract_value
9
).report()
Copied!
In addition, you can generate a PerformanceReport with compounded metrics by passing compound_metrics=True . The below code block demonstrates this feature by building on the examples provided above.
You can also generate a PerformanceReport with compounded metrics by passing compound_metrics=True. The following code block demonstrates this feature by building on the examples provided above:
1
sig.PerformanceReport(
2
rfs,
3
dates=dates[-5:],
4
views=[sig.View.SUMMARY_ROLLING_SERIES],
5
aum=first_contract_value,
6
compound_metrics=True
7
).report()
Copied!
1
sig.PerformanceReport(
2
rfs,
3
dates=dates[-5:],
4
views=[sig.View.SUMMARY_ROLLING_SERIES],
5
aum=first_contract_value,
6
compound_metrics=True
7
).report()
Copied!