用 Python 创建赢率 百分之74 的倒卖策略

介绍

最近,我暂时停止了对使用技术指标构建的常规交易策略的回测,并继续疯狂搜索以探索一些非常规策略。就在那时,我了解到了倒卖交易的概念以及市场上交易者如何使用它。

我对此很着迷,并尝试了该策略。我想出了自己的倒卖策略,并在 Python 中对其进行了回溯测试,结果非常有趣。

在本文中,我将解释我使用 Python 实现的策略以及如何开发该策略。因此,我们将首先了解有关交易策略的一些背景知识,然后继续进行编码部分,在该部分中,我们将使用FinancialModelingPrep (FMP) API数据,并在 Python 中回测我们的策略。

话不多说,让我们一起进入本文吧!

我们的倒卖交易策略

在深入研究我们的交易策略机制之前,有必要首先对倒卖交易的概念有一些了解。

倒卖交易

倒卖交易是一种非常规的交易方式,交易者旨在从微小的价格波动中获利。

例如,遵循倒卖交易的交易者会以 170 美元的价格买入大量苹果 (AAPL) 股票,并计划以非常小的价格涨幅(如 170.5 美元或 171 美元)出售该股票。

以较小的价格变化快速抛售股票的原因是每笔交易涉及大量资金。剥头皮交易只有在资金雄厚的情况下才能获得可观的利润。

交易策略

现在我们已经很好地了解了什么是剥头皮交易,让我们深入研究我们的交易策略。

因此,剥头皮交易的基本思想是从微小的价格变化中获利。显然,我们不能使用它作为我们的策略,因为它太生硬了,但我们可以做的就是将其作为我们交易策略的基础,并且我们需要在此基础上创建有效的剥头皮策略。

以下是我们交易策略的机制:

如果出现以下情况,我们入市:市场开盘价较前一日收盘价上涨 1%。

我们在以下情况退出市场:股票价格较买入价(即当日开盘价)上涨 1%。如果股票价格未能达到 1% 的涨幅,我们将在交易日结束时以收盘价退出。

这里的目标不是创建一个具有各种进入和退出条件的复杂策略,而是创建一个简单的策略来理解剥头皮交易的本质。话虽如此,让我们继续编码部分!

导入包

第一步也是最重要的一步是将所有必需的包导入到我们的 Python 环境中。在本文中,我们将使用四个包,它们是:

  • Pandas — 用于数据格式化、清除、操作和其他相关目的
  • Matplotlib — 用于创建图表和不同类型的可视化
  • request — 用于进行 API 调用以提取数据
  • Termcolor — 自定义 Jupyter Notebook 中显示的标准输出
  • math— 用于各种数学函数和运算
  • NumPy — 用于数值和高级数学函数

以下代码将上述所有包导入到我们的Python环境中:

1
2
3
4
5
6
7
# IMPORTING PACKAGES  
import requests
import pandas as pd
import matplotlib.pyplot as plt
from termcolor import colored as cl
import numpy as np
import math

如果您尚未安装任何导入的软件包,请确保使用pip终端中的命令来安装。

提取历史数据

获取股票的历史数据对于回测过程非常重要。为了数据的准确性和可靠性,我们将使用**FinancialModelingPrep (FMP) 的历史数据端点**,该端点允许提取任何特定股票的日终数据。我们将对 Tesla 股票的倒卖策略进行回测,以下代码提取 2014 年初以来的历史数据:

1
2
3
4
5
6
7
8
9
10
11
# EXTRACTING HISTORICAL DATA

api_key = 'YOUR API KEY'
tsla_json = requests.get(f'https://financialmodelingprep.com/api/v3/historical-price-full/TSLA?from=2014-01-01&apikey={api_key}').json()

tsla_df = pd.DataFrame(tsla_json['historical']).drop('label', axis = 1)
tsla_df = tsla_df.set_index('date')
tsla_df = tsla_df.iloc[::-1]
tsla_df.index = pd.to_datetime(tsla_df.index)

tsla_df

代码非常简单。我们首先将 API 密钥存储在api_key变量中。确保替换为您[创建 FMP 开发人员帐户] YOUR API KEY后可以获得的秘密 API 密钥。

然后,使用getRequests包提供的函数,我们调用API来获取TSLA的历史数据。最后,我们将提取的 JSON 响应转换为可用的 Pandas 数据帧以及一些数据操作,这是输出:

IMG_256

使用 FMP 的 API 提取的 TSLA 历史数据(作者图片)

我真正喜欢 FMP 历史数据端点提供的 API 响应的一件事是它附带的大量附加数据。除了 OHLC 数据之外,您还可以获得 VWAP、变化百分比等,这些数据在某些情况下非常有用。

计算变化百分比并过滤

根据交易策略,如果当日开盘价比前一日收盘价高1%,我们就进场。为此,我们首先需要借助获得的历史数据来计算价格变化的百分比。以下代码执行相同的操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
# CALCULATING % CHANGE

tsla_df['pclose_open_pc'] = np.nan

for i in range(1, len(tsla_df)):
diff, avg = (tsla_df.close[i-1] - tsla_df.open[i]) , (tsla_df.close[i-1] + tsla_df.open[i])/2
pct_change = (diff / avg)*100
tsla_df['pclose_open_pc'][i] = pct_change

tsla_df = tsla_df.dropna().drop(['change', 'changePercent', 'changeOverTime'], axis = 1)
tsla_df = tsla_df[tsla_df.pclose_open_pc > 1]

tsla_df

代码可能看起来有点模糊,包含所有的 for 循环和其他内容,但实际上非常简单。让我来分解一下。

首先,我们创建一个名为pclose_open_pc存储百分比变化值的新列。然后是 for 循环。这个 for 循环背后的主要思想是复制pct_change()Pandas 提供的函数的功能。

我们在 for 循环的帮助下所做的唯一改变是计算两个不同变量之间的百分比变化。即,当天的开盘价和前一天的收盘价是不可能的,但pct_change()允许计算单个变量的当前值和旧值之间的百分比变化。

之后,我们删除一些列,并使用一个条件对数据帧进行切片,该条件选择百分比变化大于 1 的行,即当天的开盘价比前一天的收盘价高 1%。

这是所有处理后的最终数据帧:

IMG_257

过滤后的 TSLA 历史数据(作者提供的图片)

现在我们已经准备好了数据,是时候实际构建和测试我们的剥头皮交易策略了。

回测策略

我们已经完成了本文中最重要和最有趣的步骤之一。现在我们已经了解了交易策略的细节,让我们用 Python 构建它并进行回测。为了简单起见,我们将遵循一个非常基本且简单的回测系统。以下代码回测了倒卖策略:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
investment = 100000
equity = investment
earning = 0

earnings_record = []

for i in range(len(tsla_df)):

# EXTRACTING INTRADAY DATA
date = str(tsla_df.index[i])[:10]
intra_json = requests.get(f'https://financialmodelingprep.com/api/v3/historical-chart/1min/TSLA?from={date}&to={date}&apikey={api_key}').json()
intra_df = pd.DataFrame(intra_json)
intra_df = intra_df.set_index(pd.to_datetime(intra_df.date)).iloc[::-1]

# ENTERING POSITION
open_p = tsla_df.iloc[i].open
no_of_shares = math.floor(equity/open_p)
equity -= (no_of_shares * open_p)

# EXITING POSITION
intra_df['p_change'] = np.nan

for i in range(len(intra_df)):
diff, avg = (intra_df.close[i] - open_p), (intra_df.close[i] + open_p)/2
pct_change = (diff / avg)*100
intra_df['p_change'][i] = pct_change
intra_df = intra_df.dropna()
greater_1 = intra_df[intra_df.p_change > 1]

if len(greater_1) > 0:
sell_price = greater_1.iloc[0].close
equity += (no_of_shares * sell_price)
else:
sell_price = intra_df.iloc[-1].close
equity += (no_of_shares * sell_price)

# CALCULATING TRADE EARNINGS
investment += earning
earning = round(equity-investment, 2)
earnings_record.append(earning)

if earning > 0:
print(cl('PROFIT:', color = 'green', attrs = ['bold']), f'Earning on {date}: ${earning}; Bought ', cl(f'{no_of_shares}', attrs = ['bold']), 'stocks at ', cl(f'${open_p}', attrs = ['bold']), 'and Sold at ', cl(f'${sell_price}', attrs = ['bold']))
else:
print(cl('LOSS:', color = 'red', attrs = ['bold']), f'Loss on {date}: ${earning}; Bought ', cl(f'{no_of_shares}', attrs = ['bold']), 'stocks at ', cl(f'${open_p}', attrs = ['bold']), 'and Sold at ', cl(f'${sell_price}', attrs = ['bold']))

我不会深入研究每一行代码,而是尝试给出这个回测系统代码的要点。

基本上,代码可以分为四个部分(如代码注释中所示):

  • 第一个是使用FMP 的日内数据端点提取我们进入市场时的日内数据。
  • 第二部分是我们通过以当天开盘价买入股票来建仓的地方。
  • 第三部分是退出仓位的代码,我们首先计算价格变化的百分比,然后一旦价格上涨 1%,我们就平仓。
  • 第四部分专门计算每笔交易的收益并将结果打印在输出终端中。

该程序进行了大量交易,虽然无法显示其中一笔交易,但以下是已执行交易的一瞥:

IMG_258

程序生成的交易(作者提供的图片)

输出包括所有必要的详细信息,例如股票数量、买入价、卖出价、日期和收益。虽然有一些亏损的交易,但大多数都是盈利的交易,收益合理。

策略回报分析与评估

在本节中,我们将深入探讨该策略的绩效。让我们从策略回报和投资回报率的基本指标开始。以下代码计算策略的总收益和投资回报率:

1
2
3
4
5
6
7
8
9
# STRATEGY RETURNS

print(cl(f'TSLA BACKTESTING RESULTS:', attrs = ['bold']))
print(' ')

strategy_earning = round(equity - 100000, 2)
roi = round(strategy_earning / 100000 * 100, 2)

print(cl(f'EARNING: ${strategy_earning} ; ROI: {roi}%', attrs = ['bold']))

代码非常简单。我们只是应用数学公式来计算总收益和投资回报率 (ROI),以得出最终数字,这是最终输出:

IMG_259

回测结果(作者图片)

因此,我们的剥头皮交易策略在十年(2014-2024)期间创造了 11 万美元的总收入,投资回报率为 110%。那还不错。虽然结果不是压倒性的,但仍然相当不错。

现在让我们使用一些基本指标来评估我们的交易策略。但为了计算这些指标,我们首先创建并处理数据:

1
2
3
4
5
earnings_df = pd.DataFrame(columns = ['date', 'earning'])
earnings_df.date = tsla_df.index
earnings_df.earning = earnings_record

earnings_df.tail()

此代码的主要目的是创建一个数据框,其中包含该策略在每个交易日产生的收益的详细信息。借助earnings_record我们在回测代码中创建的用于记录收益数据的列表,我们可以轻松地从中创建一个 Pandas 数据框,而这正是我们在代码中所做的。这是最终的输出:

IMG_260

盈利数据(作者图片)

现在我们已经有了所需的数据,我们现在可以继续计算评估我们的交易策略所需的指标。在此之前,这是我们将用于评估的指标列表:

  • 最大损失:最差交易的收益
  • 最大利润:最佳交易的收益
  • 交易总数:策略生成的交易总和
  • 胜率:策略成功的概率
  • 每月平均交易量和每月平均收益

以下代码计算所有上述讨论的指标:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
max_loss = earnings_df.earning.min()
max_profit = earnings_df.earning.max()

no_of_wins = len(earnings_df.iloc[np.where(earnings_df.earning > 0)[0]])
no_of_losses = len(earnings_df.iloc[np.where(earnings_df.earning < 0)[0]])
no_of_trades = no_of_wins+no_of_losses
win_rate = (no_of_wins/(no_of_wins + no_of_losses))*100

print(cl('MAX LOSS:', color = 'red', attrs = ['bold']), f'${max_loss};',
cl('MAX PROFIT:', color = 'green', attrs = ['bold']), f'{max_profit};',
cl('TOTAL TRADES:', attrs = ['bold']), f'{no_of_trades};',
cl('WIN RATE:', attrs = ['bold']), f'{round(win_rate)}%;',
cl('AVG. TRADES/MONTH:', attrs = ['bold']), f'{round(no_of_trades/120)};',
cl('AVG. EARNING/MONTH:', attrs = ['bold']), f'${round(strategy_earning/120)}'
)

plt.style.use('ggplot')

earnings_df.earning.hist()
plt.title('Earnings Distribution')
plt.show()

earnings_df = earnings_df.set_index('date')

earnings_df.earning.cumsum().plot()
plt.title('Strategy Cumulative Returns')
plt.show()

除了计算指标之外,代码中还涉及一些可视化,我们将在稍后讨论。这是输出:

IMG_261

IMG_262

IMG_263

策略绩效(作者提供的图片)

我们首先谈谈指标。最大损失为 $15.1k,最大利润为 $5K。问题是,最大损失的绝对值小于最大利润总是更好,因为它可以降低策略的风险。

十年间该策略产生的交易总数为 501 笔。这个数字并不压倒性,这是一件好事。一个月平均执行的交易数量为 4 笔,这也是一个合理的交易数量。每月平均回报为 923 美元,这是一个可靠的数字。

最重要的指标是胜率。我们的策略胜率是74%。这意味着我们的策略有 74% 的机会执行盈利交易,这是令人难以置信的。胜率大于 50% 的策略被认为是有效且风险较小的。但如果没有适当的风险管理系统,这个数字仍然没有任何意义。

就图表而言,在上面的输出中可以看到其中两个。第一个是直方图,显示我们策略的收益分布。可以看出,大部分交易的收益在 1500-2500 美元左右。

第二张图是折线图,显示了我们交易策略的累积收益。首先可以注意到的是线路的不稳定运动。这表明该策略的收益波动很大,这意味着我们的策略在某些情况下是不稳定且有风险的。最好避免图表中所示的突然下跌。

买入/持有回报比较

一个好的交易策略不仅应该能够产生有利可图的回报,而且必须足够有效以优于买入/持有策略。对于那些不知道什么是买入/持有策略的人来说,这是一种交易者无论情况如何都长期买入并持有股票的策略。

如果我们的策略击败了买入/持有策略,我们可以自信地说,我们想出了一个很好的交易策略,几乎可以在现实世界中部署。然而,如果做不到这一点,我们就必须对策略做出相当大的改变。

以下代码实现买入/持有策略并计算收益:

1
2
3
4
5
6
7
8
9
10
api_key = 'YOUR API KEY'
json = requests.get(f'https://financialmodelingprep.com/api/v3/historical-price-full/TSLA?from=2014-01-01&apikey={api_key}').json()

df = pd.DataFrame(json['historical']).drop('label', axis = 1)
df = df.set_index('date')
df = df.iloc[::-1]
df.index = pd.to_datetime(df.index)

tsla_roi = round(list(df['close'].pct_change().cumsum())[-1],4)*100
print(cl(f'BUY/HOLD STRATEGY ROI: {round(tsla_roi,2)}%', attrs = ['bold']))

在上面的代码中,我们再次使用FMP 的历史数据端点提取 Tesla 的历史数据,因为我们对之前提取的数据进行了一些更改。经过一些数据操作后,我们使用简单的数学来计算回报,这是最终的输出:

IMG_264

买入/持有策略投资回报率(作者图片)

在比较买入/持有策略和我们的剥头皮交易策略的结果后,买入/持有策略的投资回报率相差 333%,优于我们的策略。这是什么意思?这意味着在将其推向市场之前,我们必须在剥头皮策略上做很多工作。

结论

尽管我们经历了制定交易策略、使用历史和日内数据以及对策略进行回测的广泛过程,但我们仍然未能超越买入/持有策略。但本文的目的不是展示借助这些策略的任何赚钱方法,而是对剥头皮交易进行温和的介绍。

如果您确实想将这一策略转变为高利润策略并将其部署到市场,您可以进行一些改进来实现这一目标。首先是调整策略参数。尝试调整进入和退出条件,并测试哪一个最适合交易策略。接下来是建立适当的风险管理体系。这是我们在本文中没有讨论的内容,但它非常重要,尤其是当您想将该策略应用于现实市场时。

话虽如此,您已经到达了本文的结尾。希望您今天学到了一些新的有用的东西。如果您有任何改进交易策略的建议,请在评论中告诉我。非常感谢您的宝贵时间

© 2024 Omer Wu bar All Rights Reserved. 本站访客数人次 本站总访问量