用 Python 实现马丁格尔交易策略(附代码)
共 7618字,需浏览 16分钟
·
2022-07-10 01:45
所谓马丁格尔(Martingale)策略是在某个赌盘里,当每次「输钱」时就以2 的倍数再增加赌金,直到赢钱为止。假设在一个公平赌大小的赌盘,开大与开小都是50% 的概率,所以在任何一个时间点上,我们赢一次的概率是50%,连赢两次的概率是25%,连赢三次的概率12.5%,连赢四次的概率6.25%,以此类推。同样,连输的概率也是这样的。于是,交易上,很多人尝试马丁格尔式的金字塔加仓法来进行交易。那么马丁格尔策略是否可以增加交易者的收益?
在这篇博客中,我们将通过以下主题来关注马丁格尔及其在交易策略中的应用。扫描本文最下方二维码获取全部完整源码、CSV数据文件和Jupyter Notebook 文件打包下载。
什么是马丁格尔? 马丁格尔是如何工作的? 马丁格尔的条件期望值 马丁格尔交易策略 什么是反马丁格尔? Python中的马丁格尔与反马丁格尔交易策略
「什么是马丁格尔?」
随机变量是一个未知的值或一个函数,它在每个可能的试验中都取一个特定的值。它可以是离散的,也可以是连续的。下面我们考虑离散随机变量来解释马丁格尔。
马丁格尔是一个随机变量M1, M2, M3...Mn的序列,其中
E[Mn+1|Mn] = Mn, n -> 0, 1, ..., n+1 (1)
而E [|Mn+1|] < ∞,
读作Mn+1的期望值,因为Mn的值等于Mn,即期望值保持不变。
对于一个随机变量,不同的值x1、x2、x3,各自的概率为p1、p2和p3,其期望值的计算方法为:
E[M] = x1 * p1 + x2 * p2 + x3 * p3,更简单地说,期望值与算术平均值相同。
注意:马丁格尔总是针对一些信息集和一些概率测量来定义。如果信息集或与过程相关的概率发生变化,该过程可能不再是马丁格尔了。
「马丁格尔是如何工作的?」
考虑一个简单的游戏,你抛出一枚公平的硬币,如果结果是正面,你就赢得一美元,如果是反面,你就失去一美元。
在这个游戏中,正面或背面的概率总是一半。所以,赢的平均值等于1/2(1)+1/2(-1)=0,这意味着你不能通过玩若干轮游戏来系统地赚取任何额外的钱(尽管随机收益或损失仍然是可能的)。
因此,上述情况满足马丁格尔属性,即在任何特定回合中,无论前几回合的结果如何,你的总收入预期都会保持不变。
「马丁格尔中的条件期望值」
马丁格尔定义中方程(1)左侧的表达式被称为 "条件期望"。条件期望值(也称为条件平均数)是在一组先决条件发生后计算的平均数。
随机变量X相对于变量Z的条件期望被定义为一个(新)随机变量Y=E(X|Z)
「马丁格尔交易策略」
马丁格尔交易策略是在亏损的交易中加倍你的风险或投资规模。由于你的预期长期回报仍然是相同的(价格下跌时亏损,价格上涨时收益),这种策略可以通过在价格下跌时买入点位,降低你的平均进场价格来实现。因此,即使在一系列亏损的交易之后,如果发生了盈利的交易,它就会挽回所有的损失,包括最初的交易金额,因为它的利润是2^p=∑ 2^p-1+1。
马丁格尔法的优点和缺点。优点之一是,由于交易者在每笔亏损的交易后将投资规模加倍,该策略有助于挽回损失并产生利润,提高净收益。而主要的缺点是,你在增加投资规模时没有止损限制。
注意:如果破产,你可能会损失你的全部资本,或者导致资本缩减,需要额外的资本,如果赔率在长期内没有改善,你会不断地输。
「什么是反马丁格尔?」
在反马丁格尔策略中,当价格向有利可图的方向移动时,投资规模增加一倍,当出现损失时,投资规模减少一半。这样做的目的是希望股票在趋势中继续上涨,这在势头驱动的市场中是可行的。
反马丁格尔策略的优点和缺点。反马丁格尔策略的主要优点是在不利条件下风险最小,因为交易量在损失时不会增加。尽管有优势,但如果出现长时间的亏损交易,反马丁格尔也不会带来利润。因此,进场信号应准确计算,以避免损失覆盖所获利润。
在下一节,我们将在Python中建立马丁格尔和反马丁格尔策略。
「用 Python 实现马丁格尔与反马丁格尔交易策略」
我们使用了超过6个月的苹果公司股票(AAPL)调整后的收盘价数据。这个数据是从雅虎金融网站上提取的,并存储在一个csv文件中。
「读取股票数据」
已下载AAPL的2019年半年度(7月至12月)调整后的收盘价数据如下:
# Import the libraries , !pip install "library" for first time installing
import numpy as np, pandas as pd
!pip install pyfolio
import pyfolio as pf
import matplotlib.pyplot as plt
%matplotlib inline
plt.style.use('seaborn-darkgrid')
plt.rcParams['figure.figsize'] = (10,7)
import warnings
warnings.filterwarnings("ignore")
# Load AAPL stock csv data and store to a dataframe
df = pd.read_csv("AAPL.csv")
df = df.rename(columns={'Adj_Close': 'price'})
# Convert Date into Datetime format
df['Date'] = pd.to_datetime(df['Date'])
df.fillna(method='ffill', inplace=True)
# Set date as the index of the dataframe
df.set_index('Date',inplace=True)
df.head()
# Create a copy of two dataframes for the trading strategies
df_mg = df.copy()
df_anti_mg = df.copy()
「简单的马丁格尔策略」
马丁格尔交易策略是在亏损的交易中加倍你的交易量。
我们从AAPL的一只股票开始,在亏损的交易中把交易量或数量翻倍。构建策略时,将获胜的交易视为比前一收盘价增加2%,将失败的交易视为比前一收盘价减少2%。
# Create column for previous price
df_mg['prev_price'] = df_mg['price'].shift(1)
# Generate buy and sell signal for price increase and decrease respectively. And create consolidated 'signal' column by addition of both buy and sell signals
df_mg['long_signal'] = np.where(df_mg['price'] > 1.02*df_mg['prev_price'], 1, 0)
df_mg['short_signal'] = np.where(df_mg['price'] < .98*df_mg['prev_price'], -1, 0)
df_mg['signal'] = df_mg['short_signal'] + df_mg['long_signal']
df_mg.head()
# Initialise 'quantity' column
df_mg['quantity'] = 0
# Start with 1 stock, long position
df_mg['signal'].iloc[0] = 1
# Strategy to double the trade volume or quantity on losing trades
for i in range(df_mg.shape[0]):
if i == 0:
df_mg['quantity'].iloc[0] = 1
else:
if df_mg['signal'].iloc[i] == 1:
df_mg['quantity'].iloc[i] = df_mg['quantity'].iloc[i-1]
if df_mg['signal'].iloc[i] == -1:
df_mg['quantity'].iloc[i] = df_mg['quantity'].iloc[i-1]*2
if df_mg['signal'].iloc[i] == 0:
df_mg['quantity'].iloc[i] = df_mg['quantity'].iloc[i-1]
df_mg.head()
# Calculate returns
df_mg['returns'] = ((df_mg['price'] - df_mg['prev_price'])/ df_mg['price'])*df_mg['quantity']
# Cumulative strategy returns
df_mg['cumulative_returns'] = (df_mg.returns+1).cumprod()
# Plot cumulative returns
plt.figure(figsize=(10,5))
plt.plot(df_mg.cumulative_returns)
plt.grid()
# Define the label for the title of the figure
plt.title('Cumulative Returns for Martingale strategy', fontsize=16)
# Define the labels for x-axis and y-axis
plt.xlabel('Date', fontsize=14)
plt.ylabel('Cumulative Returns', fontsize=14)
# Define the tick size for x-axis and y-axis
plt.xticks(fontsize=12)
plt.yticks(fontsize=12)
plt.show()
# Plot position
plt.figure(figsize=(10,5))
plt.plot(df_mg.quantity)
plt.grid()
# Define the label for the title of the figure
plt.title('Position sizing', fontsize=16)
# Define the labels for x-axis and y-axis
plt.xlabel('Price', fontsize=14)
plt.ylabel('Quantity', fontsize=14)
# Define the tick size for x-axis and y-axis
plt.xticks(fontsize=12)
plt.yticks(fontsize=12)
plt.show()
注意:我们可以从上图中注意到,交易量或数量以指数形式增加,累计收益也随之增加。但在这种情况下,我们可能会耗尽资本来加倍仓位,从而导致破产。
「简单的反马丁格尔策略」
反马丁格尔策略是在获胜的交易中把交易量翻倍,在失败的交易中把交易量减半。
与上述马丁格尔策略类似,我们从AAPL的一只股票开始,在获胜的交易中把交易量或数量增加一倍,在失败的交易中把交易量或数量减少一半。该策略的建立是考虑到盈利的交易是2%的增长,而失败的交易是在前一个收盘价的基础上减少2%。
# This step before deciding trade size is same as the above martingale strategy
# Create column for previous price
df_anti_mg['prev_price'] = df_anti_mg['price'].shift(1)
# Generate buy and sell signal for price increase and decrease respectively. And create consolidated 'signal' column by addition of both buy and sell signals
df_anti_mg['long_signal'] = np.where(df_anti_mg['price'] > 1.02*df_anti_mg['prev_price'], 1, 0)
df_anti_mg['short_signal'] = np.where(df_anti_mg['price'] < .98*df_anti_mg['prev_price'], -1, 0)
df_anti_mg['signal'] = df_anti_mg['short_signal'] + df_anti_mg['long_signal']
df_anti_mg.head()
# Intialise 'quantity' column
df_anti_mg['quantity'] = 0
# Start with $10,000 cash long position
cash = 10000
df_anti_mg['signal'].iloc[0] = 1
# Strategy to double the trade volume or quantity on losing trades
for i in range(df_anti_mg.shape[0]):
if i == 0:
df_anti_mg['quantity'].iloc[0] = 1
else:
if df_anti_mg['signal'].iloc[i] == 1:
df_anti_mg['quantity'].iloc[i] = df_anti_mg['quantity'].iloc[i-1]*2
if df_anti_mg['signal'].iloc[i] == -1:
df_anti_mg['quantity'].iloc[i] = df_anti_mg['quantity'].iloc[i-1]/2
if df_anti_mg['signal'].iloc[i] == 0:
df_anti_mg['quantity'].iloc[i] = df_anti_mg['quantity'].iloc[i-1]
df_anti_mg.head()
# Calculate returns
df_anti_mg['returns'] = ((df_anti_mg['price'] - df_anti_mg['prev_price'])/ df_anti_mg['prev_price'])*df_anti_mg['quantity']
# Cumulative strategy returns
df_anti_mg['cumulative_returns'] = (df_anti_mg.returns+1).cumprod()
# Plot cumulative returns
plt.figure(figsize=(10,5))
plt.plot(df_anti_mg.cumulative_returns)
plt.grid()
# Define the label for the title of the figure
plt.title('Cumulative Returns for Anti-Martingale strategy', fontsize=16)
# Define the labels for x-axis and y-axis
plt.xlabel('Date', fontsize=14)
plt.ylabel('Cumulative Returns', fontsize=14)
# Define the tick size for x-axis and y-axis
plt.xticks(fontsize=12)
plt.yticks(fontsize=12)
plt.show()
# Plot position
plt.figure(figsize=(10,5))
plt.plot(df_anti_mg.quantity)
plt.grid()
# Define the label for the title of the figure
plt.title('Position sizing', fontsize=16)
# Define the labels for x-axis and y-axis
plt.xlabel('Date', fontsize=14)
plt.ylabel('Quantity', fontsize=14)
# Define the tick size for x-axis and y-axis
plt.xticks(fontsize=12)
plt.yticks(fontsize=12)
plt.show()
标准马丁格尔在长期内会导致高度可变的结果,因为它可能会遇到指数级增长的损失。而反马丁格尔的回报分布明显更平坦,方差更小,因为它减少了损失的风险,而增加了利润的风险。考虑到这一点,我们看到大多数成功的交易者倾向于遵循反马丁格尔策略,因为与马丁格尔策略相比,他们被认为在连胜期间增加投资规模的风险较小。
「总结」
在这篇文章中,我们首先通过条件期望值的概念了解了马丁格尔的直观含义。接下来,我们学习了马丁格尔策略的类型。在马丁格尔交易策略下,交易规模或数量在亏损的交易中翻倍,通过后面的盈利交易来弥补亏损并产生利润。在反马丁格尔交易策略中,交易规模或数量在亏损的交易中减半,在盈利的交易中翻倍。我们还了解了可能适合这两种策略的市场条件。最后,我们用Python实现了马丁格尔和反马丁格尔交易策略。
E N D
扫描本文最下方二维码获取源码和数据文件打包下载。
↓↓长按扫码获取完整源码↓↓