使用 Python 中的 VWAP 和移动平均线策略进行比特币算法交易回测。我们将深入探讨算法交易的 VWAP(成交量加权平均价格)和移动平均线 (MA) 指标的详细比较。
VWAP 和移动平均线是交易者中流行的工具,每种工具都提供独特的见解。移动平均线提供了简单的价格平均值,而 VWAP 通过结合交易量提供了更微妙的视角。这种区别对于确定证券是被高估还是被低估至关重要。我们将讨论为什么 VWAP 经常受到交易者的青睐,以及它如何作为动态支撑位和阻力位。
我将指导您完成 VWAP 的计算,强调由于其成交量加权性质,它相对于移动平均线的重要性。
第 1 步:数据导入和预处理
第一步,我们导入并预处理比特币交易数据,为分析做准备。该过程涉及以下操作:
import pandas as pd
# Load the Bitcoin trading data from a CSV file
df = pd.read_csv("BTCUSD_Candlestick_15_M_ASK_05.08.2019-29.04.2022.csv")
# Clean the "Gmt time" column by removing the ".000" suffix
df["Gmt time"] = df["Gmt time"].str.replace(".000", "")
# Convert the "Gmt time" column to datetime format
df['Gmt time'] = pd.to_datetime(df['Gmt time'], format='%d.%m.%Y %H:%M:%S')
# Set the "Gmt time" column as the index of the DataFrame
df.set_index("Gmt time", inplace=True)
# Remove rows where the high and low prices are equal
df = df[df.High != df.Low]
- Clean the "Gmt time" column 清理时间列:通过从时间戳字符串中删除".000"后缀来清理"Gmt 时间"列,以确保日期时间格式正确。
- Convert the "Gmt time" column 转换为日期时间:使用 pd.to_datetime 函数将清理后的"Gmt 时间"列转换为日期时间格式,并指定正确的解析格式。
- Remove rows 过滤数据:从 DataFrame 中删除最高价和最低价相等的行,以确保交易数据有意义。
第 2 步:计算指标
第二步,我们使用 pandas_ta 库计算 VWAP (成交量加权平均价格) 和 EMA (指数移动平均线) 指标。
import pandas_ta as ta
# Calculate VWAP (Volume Weighted Average Price) and add it to the DataFrame
df["VWAP"] = ta.vwap(df.High, df.Low, df.Close, df.Volume)
# Calculate EMA (Exponential Moving Average) with a length of 100 periods and add it to the DataFrame
df["EMA"] = ta.ema(df.Close, length=100)
- 计算 VWAP:VWAP 指标使用最高价、最低价、收盘价和成交量数据计算。VWAP 将作为名为 "VWAP" 的新列添加到 DataFrame 中。
- 计算 EMA:EMA 指标是针对指定长度为 100 个周期的收盘价计算的。EMA 将作为名为 "EMA" 的新列添加到 DataFrame 中。
第 3 步:生成 EMA 信号
在第三步中,我们根据指数移动平均线 (EMA) 生成交易信号。这些信号将帮助我们确定潜在的买入和卖出机会。我们根据指定回溯期内的最高价、最低价和 EMA 值之间的关系来识别潜在的交易信号。
该信号检查回溯期内的所有蜡烛是否完全高于或完全低于 EMA。如果它们都在上方,则表明上升趋势;如果它们都低于下方,则表明 backcandles 窗口内出现下降趋势。
# Initialize the EMASignal list with zeros
emasignal = [0] * len(df)
# Define the lookback period
backcandles = 6
# Loop through the DataFrame starting from the lookback period to the end
for row in range(backcandles, len(df)):
upt = 1
dnt = 1
# Check the conditions for the past backcandles periods
for i in range(row - backcandles, row + 1):
if df.High[i] >= df.EMA[i]:
dnt = 0
if df.Low[i] <= df.EMA[i]:
upt = 0
# Set the EMASignal based on the conditions
if upt == 1and dnt == 1:
emasignal[row] = 3
elif upt == 1:
emasignal[row] = 2
elif dnt == 1:
emasignal[row] = 1
# Add the EMASignal to the DataFrame
df['EMASignal'] = emasignal
/var/folders/d9/rbb57jqn3g133_ynk3vgz02c0000gn/T/ipykernel_38122/1407699409.py:13: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`
if df.High[i] >= df.EMA[i]:
/var/folders/d9/rbb57jqn3g133_ynk3vgz02c0000gn/T/ipykernel_38122/1407699409.py:15: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`
if df.Low[i] <= df.EMA[i]:
- 初始化信号列表:我们创建一个名为 emasignal 的列表,其中填充了零,对应于 DataFrame 的长度。
- 设置回溯周期: 我们定义一个变量 backcandles 来指定我们将回溯以检查信号条件的周期数。
- 遍历数据:我们从 backcandles 索引开始遍历 DataFrame,直到 DataFrame 的末尾。
- 检查条件:对于每一行,我们将两个变量 upt 和 dnt 初始化为 1,分别表示上升和下降趋势。然后,我们遍历过去的 backcandles 周期以检查以下条件:
- 如果当前蜡烛的最高价大于或等于 EMA,则将 dnt 设置为 0。
- 如果当前蜡烛的最低价小于或等于 EMA,则设置为 0。
- 设置信号:
- 如果 upt 和 dnt 都保持 1,则将信号设置为 3(表示没有明显的趋势)。
- 如果只有 upt 为 1,则将信号设置为 2 (表示潜在的上升趋势)。
- 如果只有 dnt 为 1,则将信号设置为 1(表示潜在的下降趋势)。
向 DataFrame 添加信号:最后,我们将生成的信号添加到 DataFrame 中名为 EMASignal 的新列中。
python 代码也可以使用切片编写,这更像是一种 python 编码方式:
# Initialize the EMASignal list with zeros
emasignal = [0] * len(df)
# Define the lookback period
backcandles = 6
# Loop through the DataFrame starting from the lookback period to the end
for row in range(backcandles, len(df)):
# Slicing the relevant window of high, low, and EMA values
high_slice = df.High[row - backcandles: row + 1]
low_slice = df.Low[row - backcandles: row + 1]
ema_slice = df.EMA[row - backcandles: row + 1]
# Check the conditions for uptrend and downtrend
upt = all(high_slice >= ema_slice)
dnt = all(low_slice <= ema_slice)
# Set the EMASignal based on the conditions
if upt and dnt:
emasignal[row] = 3
elif upt:
emasignal[row] = 2
elif dnt:
emasignal[row] = 1
# Add the EMASignal to the DataFrame
df['EMASignal'] = emasignal