Home  >  Article  >  Backend Development  >  Trading strategies and portfolio analysis using Python

Trading strategies and portfolio analysis using Python

王林
王林forward
2023-05-18 13:13:061780browse

We will measure the performance of trading strategies in this article. And will develop a simple momentum trading strategy that will use four asset classes: bonds, stocks, and real estate. These asset classes have low correlations, which makes them excellent risk-balancing options.

Trading strategies and portfolio analysis using Python

Momentum Trading Strategy

This strategy is based on momentum because traders and investors have long been aware of the impact of momentum, which can be seen in a wide range of market and time frame as seen. So we call it a momentum strategy. Trend following or time series momentum (TSM) is another name for using these strategies on a single instrument. We will create a basic momentum strategy and test it on TCS to see how it performs.

TSM Strategy Analysis

First, we will import some libraries

import numpy as np
 import pandas as pd
 import matplotlib.pyplot as plt
 import yfinance as yf
 import ffn
 %matplotlib inline

We build the basic momentum strategy function TSMStrategy. The function will return the expected performance via the logarithmic return of the time series, the time period of interest, and a Boolean variable for whether shorting is allowed.

def TSMStrategy(returns, period=1, shorts=False):
if shorts:
position = returns.rolling(period).mean().map(
lambda x: -1 if x <= 0 else 1)
else:
position = returns.rolling(period).mean().map(
lambda x: 0 if x <= 0 else 1)
performance = position.shift(1) * returns
return performance
 ticker = 'TCS'
 yftcs = yf.Ticker(ticker)
 data = yftcs.history(start='2005-01-01', end='2021-12-31')
 returns = np.log(data['Close'] / data['Close'].shift(1)).dropna()
 performance = TSMStrategy(returns, period=1, shorts=False).dropna()
 years = (performance.index.max() - performance.index.min()).days / 365
 perf_cum = np.exp(performance.cumsum())
 tot = perf_cum[-1] - 1
 ann = perf_cum[-1] ** (1 / years) - 1
 vol = performance.std() * np.sqrt(252)
 rfr = 0.02
 sharpe = (ann - rfr) / vol
 print(f"1-day TSM Strategy yields:" +
f"nt{tot*100:.2f}% total returns" +
f"nt{ann*100:.2f}% annual returns" +
f"nt{sharpe:.2f} Sharpe Ratio")
 tcs_ret = np.exp(returns.cumsum())
 b_tot = tcs_ret[-1] - 1
 b_ann = tcs_ret[-1] ** (1 / years) - 1
 b_vol = returns.std() * np.sqrt(252)
 b_sharpe = (b_ann - rfr) / b_vol
 print(f"Baseline Buy-and-Hold Strategy yields:" +
f"nt{b_tot*100:.2f}% total returns" +
f"nt{b_ann*100:.2f}% annual returns" +
f"nt{b_sharpe:.2f} Sharpe Ratio")

The function output is as follows:

1-day TSM Strategy yields:
 -45.15% total returns
 -7.10% annual returns
 -0.17 Sharpe Ratio
 Baseline Buy-and-Hold Strategy yields:
 -70.15% total returns
 -13.78% annual returns
 -0.22 Sharpe Ratio

In terms of reasonable annualized returns, the 1-day TSM strategy is better than the buy and hold strategy. Because a 1-day lookback can contain many false trends, we tried different time periods to see how they compare. Here the model will be run in a loop for 3, 5, 15, 30 and 90 days.

 import matplotlib.gridspec as gridspec
 periods = [3, 5, 15, 30, 90]
 fig = plt.figure(figsize=(12, 10))
 gs = fig.add_gridspec(4, 4)
 ax0 = fig.add_subplot(gs[:2, :4])
 ax1 = fig.add_subplot(gs[2:, :2])
 ax2 = fig.add_subplot(gs[2:, 2:])
 ax0.plot((np.exp(returns.cumsum()) - 1) * 100, label=ticker, linestyle='-')
 perf_dict = {'tot_ret': {'buy_and_hold': (np.exp(returns.sum()) - 1)}}
 perf_dict['ann_ret'] = {'buy_and_hold': b_ann}
 perf_dict['sharpe'] = {'buy_and_hold': b_sharpe}
 for p in periods:
log_perf = TSMStrategy(returns, period=p, shorts=False)
perf = np.exp(log_perf.cumsum())
perf_dict['tot_ret'][p] = (perf[-1] - 1)
ann = (perf[-1] ** (1/years) - 1)
perf_dict['ann_ret'][p] = ann
vol = log_perf.std() * np.sqrt(252)
perf_dict['sharpe'][p] = (ann - rfr) / vol
ax0.plot((perf - 1) * 100, label=f'{p}-Day Mean')
 
 ax0.set_ylabel('Returns (%)')
 ax0.set_xlabel('Date')
 ax0.set_title('Cumulative Returns')
 ax0.grid()
 ax0.legend()
 _ = [ax1.bar(i, v * 100) for i, v in enumerate(perf_dict['ann_ret'].values())]
 ax1.set_xticks([i for i, k in enumerate(perf_dict['ann_ret'])])
 ax1.set_xticklabels([f'{k}-Day Mean'
if type(k) is int else ticker for
k in perf_dict['ann_ret'].keys()],
rotation=45)
 ax1.grid()
 ax1.set_ylabel('Returns (%)')
 ax1.set_xlabel('Strategy')
 ax1.set_title('Annual Returns')
 _ = [ax2.bar(i, v) for i, v in enumerate(perf_dict['sharpe'].values())]
 ax2.set_xticks([i for i, k in enumerate(perf_dict['sharpe'])])
 ax2.set_xticklabels([f'{k}-Day Mean'
if type(k) is int else ticker for
k in perf_dict['sharpe'].keys()],
rotation=45)
 ax2.grid()
 ax2.set_ylabel('Sharpe Ratio')
 ax2.set_xlabel('Strategy')
 ax2.set_title('Sharpe Ratio')
 plt.tight_layout()
 plt.show()

Trading strategies and portfolio analysis using Python

Looking at the results on the chart, we can see that the 15-day momentum indicator provides the best results. However, the results for other time periods are mixed. This shows that our strategy is not reliable. So we can also exit the trade by using a stop or trailing stop near the top, rather than doing it when the 15-day chart is down or flat.

PORTFOLIO ANALYSIS

So far we have created a trading strategy in Python. Below we will measure and plot common portfolio characteristics to facilitate our observation and analysis.

Portfolio Analysis

First, we will import some important libraries and observe the data execution.

import pandas_datareader.data as web
 stocks = ['SPY','GLD','TLT','HYG']
 
 data = web.DataReader(stocks,data_source='yahoo',start='01/01/2019')['Adj Close']
 data.sort_index(ascending=True,inplace=True)
 perf = data.calc_stats()
 perf.plot()

Trading strategies and portfolio analysis using Python

Logarithmic Return

Logarithmic return is used to calculate exponential growth rate. Instead of calculating the percentage price change for each sub-period, we calculate the organic growth index for that period. First create a df that contains the log return of each stock price in the data, then we create a histogram for each log return.

 returns = data.to_log_returns().dropna()
 print(returns.head())
 
 
 Symbols SPY GLD TLT HYG
 Date
 2019-01-03 -0.024152 0.009025 0.011315 0.000494
 2019-01-04 0.032947 -0.008119 -0.011642 0.016644
 2019-01-07 0.007854 0.003453 -0.002953 0.009663
 2019-01-08 0.009351 -0.002712 -0.002631 0.006470
 2019-01-09 0.004663 0.006398 -0.001566 0.001193

The histograms are as follows:

ax = returns.hist(figsize=(20, 10),bins=30)

Trading strategies and portfolio analysis using Python

Histograms showing normal distribution for all four asset classes. A sample with a normal distribution has an arithmetic mean and an equal distribution above and below the mean (the normal distribution also known as the Gaussian distribution is symmetrical). If returns are normally distributed, more than 99% of returns are expected to fall within three standard deviations of the mean. These bell-shaped normal distribution characteristics allow analysts and investors to make better statistical inferences about a stock's expected returns and risks. Stocks with a bell curve are typically blue chips with low and predictable volatility.

Maximum retracement rate DRAWDOWN

DRAWDOWN refers to the value falling to a relative low. This is an important risk factor for investors to consider. Let us draw a visual representation of the decreasing strategy.

ffn.to_drawdown_series(data).plot(figsize=(15,10))

Trading strategies and portfolio analysis using Python

All four assets declined in the first half of 2020, with SPY experiencing the largest decline of 0.5%. Then, in the first half of 2020, all assets recovered immediately. This indicates a high asset recovery rate. These assets peaked around July 2020. Following this trend, all asset classes saw modest declines once the recovery peaked. According to the results, TLT will experience the largest decline of 0.5% in the second half of 2022 before recovering by early 2023.

MARKOWITZ Mean-variance optimization

In 1952, Markowitz (MARKOWITZ) proposed the mean-variance portfolio theory, also known as modern portfolio theory. Investors can use these concepts to construct a portfolio that maximizes expected returns based on a given level of risk. Based on the Markowitz method, we can generate an "optimal portfolio".

returns.calc_mean_var_weights().as_format('.2%')
 #结果
 SPY 46.60%
 GLD 53.40%
 TLT 0.00%
 HYG 0.00%
 dtype: object

Correlation Statistics

Correlation is a statistical method used to measure the relationship between securities. This information is best viewed using heat maps. Heatmaps allow us to see correlations between securities.

returns.plot_corr_heatmap()

Trading strategies and portfolio analysis using Python

最好在你的投资组合中拥有相关性较低的资产。除了SPY与HYG,这四个资产类别的相关性都很低,这对我们的投资组合是不利的:因为如果拥有高度相关的不同资产组,即使你将风险分散在它们之间,从投资组合构建的角度来看,收益也会很少。

总结

通过分析和绘制的所有数据进行资产配置,可以建立一个投资组合,极大地改变基础投资的风险特征。还有很多我没有提到的,但可以帮助我们确定交易策略价值的起点。我们将在后续文章中添加更多的技术性能指标。

The above is the detailed content of Trading strategies and portfolio analysis using Python. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:51cto.com. If there is any infringement, please contact admin@php.cn delete