Python 中的 VWAP 算法策略

[文献精汇]Python 中的 VWAP 算法策略

使用 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
相关推荐
多多*9 分钟前
微服务网关SpringCloudGateway+SaToken鉴权
linux·开发语言·redis·python·sql·log4j·bootstrap
梓仁沐白10 分钟前
【Kotlin】协程
开发语言·python·kotlin
Java Fans26 分钟前
在WPF项目中集成Python:Python.NET深度实战指南
python·.net·wpf
Cyanto29 分钟前
Java并发编程面试题
java·开发语言·面试
海的诗篇_36 分钟前
前端开发面试题总结-JavaScript篇(一)
开发语言·前端·javascript·学习·面试
小wanga1 小时前
【递归、搜索与回溯】专题三 穷举vs暴搜vs回溯vs剪枝
c++·算法·机器学习·剪枝
じ☆ve 清风°1 小时前
理解JavaScript中map和parseInt的陷阱:一个常见的面试题解析
开发语言·javascript·ecmascript
豌豆花下猫1 小时前
Python 潮流周刊#105:Dify突破10万星、2025全栈开发的最佳实践
后端·python·ai
天宫风子1 小时前
线性代数小述(一)
线性代数·算法·矩阵·抽象代数
sss191s1 小时前
Java 集合面试题从数据结构到 HashMap 源码剖析详解及常见考点梳理
java·开发语言·数据结构