目录
在股票交易中,传统技术指标(如MACD、RSI)常因滞后性错过最佳买卖点。本文将融合物理学中的能量场理论,提出一个创新指标——市场能量潮(Market Energy Tide, MET),通过量化价格、成交量、波动率的能量转换,提前识别趋势转折点。文末提供可直接运行的Python代码,助你实战验证。
一、传统指标的局限性
1. 常见指标分析
- 趋势线斜率:依赖主观画线,难以量化;
- RSI/MACD:基于历史价格计算,信号滞后;
- 波动率指标(ATR):反映幅度但无法预判方向。
2. 核心痛点
- 维度单一:仅考虑价格或成交量;
- 噪声干扰:震荡市中假信号频发;
- 缺乏能量视角:未衡量市场多空力量的“积蓄-爆发-衰竭”过程。
二、能量场理论:重新定义市场动力学
1.理论基础与创新点
能量守恒定律的金融化:
将价格动能(K)、成交量势能(V)、波动率热能(H)视为市场能量的三大来源,三者相互转化,形成「能量场」。
- 价格动能(K):价格变化的加速度(二阶导数),代表趋势惯性。
- 成交量势能(V):成交量对价格变化的支撑强度,类似“燃料”。
- 波动率热能(H):市场情绪的热度,高波动率加速能量释放。
核心逻辑:
- 能量积累阶段:价格缓涨+缩量+低波动 → 能量场积蓄。
- 能量爆发阶段:价格陡升+放量+高波动 → 能量释放,进入主升浪。
- 能量衰竭阶段:价格滞涨+量能背离 → 能量场衰减,趋势反转。
2.指标公式与计算步骤
能量场强度(Energy Field Intensity, EFI)
E F I t = α ⋅ K t + β ⋅ V t + γ ⋅ H t EFI_t=α⋅K _t+β⋅V_t+γ⋅H_t EFIt=α⋅Kt+β⋅Vt+γ⋅Ht
- 参数:
- α,β,γ 为权重系数(默认各1/3,可优化)。
- K t = d 2 P / d t 2 K_t=d^2P/dt^2 Kt=d2P/dt2(价格二阶导数,反映加速度)。
- V t = 成交 量 t / E M A ( 成交量 , N ) V_t=成交量_t/EMA(成交量,N) Vt=成交量t/EMA(成交量,N)(成交量相对强度)。
- H t = A T R t / E M A ( A T R , N ) H_t=ATR_t/EMA(ATR,N) Ht=ATRt/EMA(ATR,N)(波动率相对强度)。
- 动态调整权重:
- 当 V t V_t Vt>1(放量)时,提高 β 权重,强化量能影响;
- 当 H t H_t Ht>1(高波动)时,降低γ 权重,避免噪声干扰。
- 信号规则
- 买入信号:
EFI > 0.6 且能量方向向上,成交量突破前高。 - 卖出信号:
EFI < 0.4 且能量方向向下,价格-EFI顶背离。
- 买入信号:
3.Python代码实现1.0(核心逻辑)
import yfinance as yf
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib import gridspec
# 计算ATR(平均真实波幅)
def calculate_ATR(df, period=14):
df['H-L'] = df['High'] - df['Low']
df['H-PC'] = abs(df['High'] - df['Close'].shift(1))
df['L-PC'] = abs(df['Low'] - df['Close'].shift(1))
df['TR'] = df[['H-L', 'H-PC', 'L-PC']].max(axis=1)
df['ATR'] = df['TR'].rolling(period).mean()
return df.drop(['H-L', 'H-PC', 'L-PC', 'TR'], axis=1)
# 市场能量潮(MET)指标计算
def calculate_MET(df, period=14):
# 价格二阶导数(使用5日均线的加速度)
df['MA5'] = df['Close'].rolling(5).mean()
df['Price_Derivative2'] = df['MA5'].diff().diff()
# 成交量势能
df['Volume_EMA'] = df['Volume'].ewm(span=period).mean()
df['V_t'] = df['Volume'] / df['Volume_EMA']
# 波动率热能(ATR相对强度)
df = calculate_ATR(df, period)
df['ATR_EMA'] = df['ATR'].ewm(span=period).mean()
df['H_t'] = df['ATR'] / df['ATR_EMA']
# 动态权重调整
df['Beta'] = np.where(df['V_t'] > 1, 0.5, 0.3)
df['Gamma'] = np.where(df['H_t'] > 1, 0.2, 0.3)
df['Alpha'] = 1 - df['Beta'] - df['Gamma']
# 标准化处理(消除量纲影响)
df['Price_Derivative2_norm'] = (df['Price_Derivative2'] - df['Price_Derivative2'].rolling(50).mean()) / df[
'Price_Derivative2'].rolling(50).std()
df['V_t_norm'] = (df['V_t'] - df['V_t'].rolling(50).mean()) / df['V_t'].rolling(50).std()
df['H_t_norm'] = (df['H_t'] - df['H_t'].rolling(50).mean()) / df['H_t'].rolling(50).std()
# 计算能量场强度EFI
df['EFI'] = df['Alpha'] * df['Price_Derivative2_norm'] + df['Beta'] * df['V_t_norm'] + df['Gamma'] * df['H_t_norm']
# 计算MET方向(3日EMA平滑)
df['MET_Direction'] = df['EFI'].diff().ewm(span=3).mean()
# 生成交易信号
df['Buy_Signal'] = (df['EFI'] > 0.6) & (df['MET_Direction'] > 0)
df['Sell_Signal'] = (df['EFI'] < 0.4) & (df['MET_Direction'] < 0)
return df
# 可视化函数
def visualize_MET(df, ticker):
plt.figure(figsize=(16, 12))
gs = gridspec.GridSpec(3, 1, height_ratios=[3, 1, 2])
# 价格走势和交易信号
ax1 = plt.subplot(gs[0])
ax1.plot(df['Close'], label='Price', linewidth=1)
ax1.scatter(df.index[df['Buy_Signal']], df['Close'][df['Buy_Signal']],
marker='^', color='g', s=100, label='Buy Signal')
ax1.scatter(df.index[df['Sell_Signal']], df['Close'][df['Sell_Signal']],
marker='v', color='r', s=100, label='Sell Signal')
ax1.set_title(f'{ticker} Price with MET Signals')
ax1.legend()
# 能量场强度EFI
ax2 = plt.subplot(gs[1])
ax2.plot(df['EFI'], label='Energy Field Intensity', color='purple')
ax2.axhline(0.6, linestyle='--', color='orange')
ax2.axhline(0.4, linestyle='--', color='blue')
ax2.fill_between(df.index, df['EFI'], 0.6, where=(df['EFI'] >= 0.6),
facecolor='red', alpha=0.3)
ax2.fill_between(df.index, df['EFI'], 0.4, where=(df['EFI'] <= 0.4),
facecolor='green', alpha=0.3)
ax2.set_ylim(0, 1)
ax2.legend()
# MET方向
ax3 = plt.subplot(gs[2])
ax3.bar(df.index, df['MET_Direction'], color=np.where(df['MET_Direction'] > 0, 'g', 'r'))
ax3.set_title('MET Direction (Energy Flow)')
plt.tight_layout()
plt.show()
# 主程序
if __name__ == "__main__":
# 参数设置
ticker = '002364.yahoo' # 改为你要分析的股票代码
start_date = '2025-01-01'
end_date = '2025-03-02'
# 获取数据
print(f"Downloading {ticker} data...")
df = yf.download(ticker, start=start_date, end=end_date)
# 计算指标
print("Calculating MET indicators...")
df = calculate_MET(df)
# 可视化结果
print("Generating visualization...")
visualize_MET(df, ticker)
# 显示最近20天的EFI值
print("\nRecent EFI Values:")
print(df[['Close', 'EFI', 'MET_Direction']].tail(20))
4.Python代码优化2.0
# 导入必要的库
import tushare as ts
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib import gridspec
# 初始化pro接口
pro = ts.pro_api('token') # 请替换为您的Tushare token
# 计算ATR(平均真实波幅)
def calculate_ATR(df, period=14):
df['H-L'] = df['high'] - df['low']
df['H-PC'] = abs(df['high'] - df['close'].shift(1))
df['L-PC'] = abs(df['low'] - df['close'].shift(1))
df['TR'] = df[['H-L', 'H-PC', 'L-PC']].max(axis=1)
df['ATR'] = df['TR'].rolling(period).mean()
return df.drop(['H-L', 'H-PC', 'L-PC', 'TR'], axis=1)
# 市场能量潮(MET)指标计算
def calculate_MET(df, period=14):
# 价格二阶导数(优化为3日均线加速度)
df['MA3'] = df['close'].rolling(3).mean()
df['Price_Derivative2'] = df['MA3'].diff().diff()
# 成交量势能(增加异常值处理)
df['Volume_EMA'] = df['vol'].ewm(span=period, min_periods=5).mean()
df['V_t'] = np.clip(df['vol'] / df['Volume_EMA'], 0.5, 2.0) # 限制在0.5-2之间
# 波动率热能(优化EMA计算周期)
df = calculate_ATR(df, period)
df['ATR_EMA'] = df['ATR'].ewm(span=period * 2).mean() # 延长EMA周期
df['H_t'] = df['ATR'] / df['ATR_EMA']
# 动态权重系统(三段式分配)
conditions_gamma = [
df['H_t'] < 0.3, # 低波动
(df['H_t'] >= 0.3) & (df['H_t'] < 0.6), # 中波动
(df['H_t'] >= 0.6) & (df['H_t'] < 1.0), # 高波动
df['H_t'] >= 1.0 # 极端波动
]
choices_gamma = [0.2, 0.35, 0.5, 0.65] # 最高权重提升至0.65
df['Gamma'] = np.select(conditions_gamma, choices_gamma, default=0.4)
conditions_beta = [
df['V_t'] < 0.8,
(df['V_t'] >= 0.8) & (df['V_t'] < 1.2),
df['V_t'] >= 1.2
]
choices_beta = [0.15, 0.3, 0.45]
df['Beta'] = np.select(conditions_beta, choices_beta, default=0.3)
df['Alpha'] = 1 - df['Beta'] - df['Gamma']
# 自适应标准化(动态窗口)
volatility_window = df['ATR'].rolling(20).mean() * 10 # 根据波动率调整窗口
df['Price_Derivative2_norm'] = (df['Price_Derivative2'] - df['Price_Derivative2'].rolling(50).mean()) / df[
'Price_Derivative2'].rolling(50).std()
df['V_t_norm'] = (df['V_t'] - df['V_t'].rolling(50).mean()) / df['V_t'].rolling(50).std()
df['H_t_norm'] = (df['H_t'] - df['H_t'].rolling(50).mean()) / df['H_t'].rolling(50).std()
# 能量场计算(增加非线性变换)
df['EFI'] = (
df['Alpha'] * np.tanh(df['Price_Derivative2_norm']) +
df['Beta'] * np.log1p(df['V_t_norm']) +
df['Gamma'] * (df['H_t_norm'] ** 2)
)
# MET方向计算(带波动率加权)
df['MET_Direction'] = df['EFI'].diff().ewm(
span=3,
adjust=False
).mean() * (1 + df['H_t'] / 10) # 波动越大方向信号越强
# 动态阈值系统
atr_ratio = df['ATR'] / df['ATR'].rolling(20).mean()
df['Buy_Threshold'] = 0.55 + 0.15 * atr_ratio
df['Sell_Threshold'] = 0.45 - 0.15 * atr_ratio
# 动量过滤系统
df['Momentum_3'] = df['close'].pct_change(3)
df['Momentum_5'] = df['close'].pct_change(5)
df['Trend_EMA21'] = df['close'].ewm(span=21).mean()
# 复合交易信号
df['Buy_Signal'] = (
(df['EFI'] > df['Buy_Threshold']) &
(df['MET_Direction'] > 0) &
(df['Momentum_3'] > 0) &
(df['Momentum_5'] > 0) &
(df['close'] > df['Trend_EMA21'])
)
df['Sell_Signal'] = (
(df['EFI'] < df['Sell_Threshold']) &
(df['MET_Direction'] < 0) &
(df['Momentum_3'] < 0)
)
return df.drop(['MA3', 'Trend_EMA21'], axis=1) # 清理中间列
# 可视化函数
def visualize_MET(df, ticker):
plt.figure(figsize=(16, 12))
gs = gridspec.GridSpec(3, 1, height_ratios=[3, 1, 2])
# 价格走势和交易信号
ax1 = plt.subplot(gs[0])
ax1.plot(df['trade_date'], df['close'], label='Price', linewidth=1)
ax1.scatter(df['trade_date'][df['Buy_Signal']], df['close'][df['Buy_Signal']],
marker='^', color='g', s=100, label='Buy Signal')
ax1.scatter(df['trade_date'][df['Sell_Signal']], df['close'][df['Sell_Signal']],
marker='v', color='r', s=100, label='Sell Signal')
ax1.set_title(f'{ticker} Price with MET Signals')
ax1.set_xlabel('Date')
ax1.set_ylabel('Price')
ax1.legend()
# 能量场强度EFI
ax2 = plt.subplot(gs[1])
ax2.plot(df['trade_date'], df['EFI'], label='Energy Field Intensity', color='purple')
ax2.axhline(0.6, linestyle='--', color='orange')
ax2.axhline(0.4, linestyle='--', color='blue')
ax2.fill_between(df['trade_date'], df['EFI'], 0.6, where=(df['EFI'] >= 0.6),
facecolor='red', alpha=0.3)
ax2.fill_between(df['trade_date'], df['EFI'], 0.4, where=(df['EFI'] <= 0.4),
facecolor='green', alpha=0.3)
ax2.set_ylim(0, 1)
ax2.set_xlabel('Date')
ax2.set_ylabel('EFI')
ax2.legend()
# MET方向
ax3 = plt.subplot(gs[2])
ax3.bar(df['trade_date'], df['MET_Direction'], color=np.where(df['MET_Direction'] > 0, 'g', 'r'))
ax3.set_title('MET Direction (Energy Flow)')
ax3.set_xlabel('Date')
ax3.set_ylabel('MET Direction')
plt.tight_layout()
plt.show()
# 主程序
if __name__ == "__main__":
# 参数设置
ticker = '603118.SH' # 改为你要分析的股票代码
start_date = '20241001'
end_date = '20250303'
# 获取数据
print(f"Downloading {ticker} data...")
df = pro.daily(ts_code=ticker, start_date=start_date, end_date=end_date)
# 确保数据按日期升序排列
df['trade_date'] = pd.to_datetime(df['trade_date'], format='%Y%m%d')
df = df.sort_values(by='trade_date')
# 检查数据是否有缺失值
if df.isnull().values.any():
print("数据包含缺失值,需要处理缺失值")
df.dropna(inplace=True)
# 确保amount和close是数值类型
df['vol'] = pd.to_numeric(df['vol'], errors='coerce')
df['close'] = pd.to_numeric(df['close'], errors='coerce')
df['high'] = pd.to_numeric(df['high'], errors='coerce')
df['low'] = pd.to_numeric(df['low'], errors='coerce')
# 计算指标
print("Calculating MET indicators...")
df = calculate_MET(df)
# 可视化结果
print("Generating visualization...")
visualize_MET(df, ticker)
# 显示指定日期范围内的EFI值
print("\nEFI Values from {} to {}:".format(start_date, end_date))
print(df[['close', 'EFI', 'MET_Direction']])