大家好,我是花姐,今天带来一个冷门但极具实战价值的振荡器指标------Cybernetic Oscillator ,简称:CyberOsc。
这个指标可能你第一次听说,甚至连图都没看过,但我可以直接说重点:
它是真·没有延迟的震荡器,来自信号处理领域的大佬 John Ehlers,既能捕捉趋势,又能回避噪声,关键还自带归一化。
你可能在想------不就一个震荡器吗?又不是 RSI、MACD,还要搞得这么复杂?
那你可能小看了 Ehlers这老哥的实力了......
这人谁啊?他怎么跟炒股扯上关系了?
John F. Ehlers,是信号处理出身的工程师,后来转行搞量化,几十年来一直在研究"怎么用滤波器去除K线的噪声"。
他最牛的一点是:他从不盲目相信价格,而是把价格当成"噪声信号",用物理学方式去提纯它。
他发明了一堆神奇的指标,比如:
- SuperSmoother Filter(超平滑滤波)
- Decycler(去周期滤波)
- Roofing Filter(屋顶滤波器)
在 2024 年 6 月 TASC 杂志里,他又甩出来一个新工具------就是今天的主角:
Cybernetic Oscillator:你可以理解成"低延迟的归一化价格震荡器"。
原理讲清楚:3步搞定CyberOsc
简单粗暴理解下它的构造:
- 高通滤波器:去掉长期趋势干扰(提取短期变化)
- 低通滤波器:再把多余的噪声滤掉
- 归一化:标准化振幅,方便识别超买超卖
通俗点说,它比 RSI 更聪明、比 MACD 更灵活、比 KDJ 更少骗线。
花姐手动撸出来的Python代码如下:
python
import numpy as np
import pandas as pd
def highpass_filter(series, length):
alpha = (np.cos(np.pi * 1 / length) + np.sin(np.pi * 1 / length) - 1) / np.cos(np.pi * 1 / length)
hp = pd.Series(index=series.index, dtype='float64')
hp.iloc[0:2] = 0
for i in range(2, len(series)):
hp.iloc[i] = 0.5 * (1 + alpha) * (series.iloc[i] - series.iloc[i-1]) + (1 - alpha) * hp.iloc[i-1]
return hp
def supersmoother(series, length):
a1 = np.exp(-1.414 * np.pi / length)
b1 = 2 * a1 * np.cos(1.414 * np.pi / length)
c2 = b1
c3 = -a1 * a1
c1 = 1 - c2 - c3
ss = pd.Series(index=series.index, dtype='float64')
ss.iloc[0:2] = series.iloc[0:2]
for i in range(2, len(series)):
ss.iloc[i] = c1 * series.iloc[i] + c2 * ss.iloc[i-1] + c3 * ss.iloc[i-2]
return ss
def cyber_oscillator(series, hp_len=30, lp_len=20, norm_window=100):
hp = highpass_filter(series, hp_len)
lp = supersmoother(hp, lp_len)
rms = lp.rolling(norm_window).apply(lambda x: np.sqrt(np.mean(np.square(x))), raw=True)
return lp / (rms.replace(0, np.nan))
画个图看看效果
这里我用AKShare库获取了某个股票的历史日线行情,然后绘制了k线和2条CyberOsc指标线
python
import cyber_osc
import akshare as ak
import mplfinance as mpf
import matplotlib.pyplot as plt
import pandas as pd
# 获取xxxxx股票的日K线(支持到分钟级)
df = ak.stock_zh_a_hist(symbol="换成你的股票代码",period='daily',start_date='20000101',adjust='hfq') # 深交所的要用 sz 开头
# 统一列名
df.rename(columns={
'日期': 'date',
'开盘': 'Open',
'最高': 'High',
'最低': 'Low',
'收盘': 'Close',
'成交量': 'Volume',
}, inplace=True)
# 设置时间索引,排序
df['date'] = pd.to_datetime(df['date'])
df.set_index('date', inplace=True)
df = df[['Open', 'High', 'Low', 'Close', 'Volume']]
df.sort_index(inplace=True)
df['CyberOsc1'] = cyber_osc.cyber_oscillator(df['Close'], hp_len=30, lp_len=20)
df['CyberOsc2'] = cyber_osc.cyber_oscillator(df['Close'], hp_len=250, lp_len=20)
# print(df)
# 截取最近500天的数据
df_plot = df[-500:].copy()
# 创建图表
fig = mpf.figure(style='yahoo', figsize=(14, 8))
gs = fig.add_gridspec(4, 1) # 总共4格,K线占2格
ax1 = fig.add_subplot(gs[0:2, 0]) # K线图,占前2格
ax2 = fig.add_subplot(gs[2, 0], sharex=ax1) # CyberOsc1
ax3 = fig.add_subplot(gs[3, 0], sharex=ax1) # CyberOsc2
# 绘制K线
mpf.plot(df_plot, type='candle', ax=ax1, volume=False, show_nontrading=True)
# 绘制CyberOsc1
ax2.plot(df_plot.index, df_plot['CyberOsc1'], label='CyberOsc1', color='blue')
ax2.axhline(0, color='gray', linestyle='--', linewidth=1)
ax2.set_ylabel('CyberOsc1')
ax2.legend()
ax2.grid(True)
# 绘制CyberOsc2
ax3.plot(df_plot.index, df_plot['CyberOsc2'], label='CyberOsc2', color='orange')
ax3.axhline(0, color='gray', linestyle='--', linewidth=1)
ax3.set_ylabel('CyberOsc2')
ax3.legend()
ax3.grid(True)
plt.suptitle('kline + CyberOsc', fontsize=14)
plt.tight_layout()
plt.subplots_adjust(top=0.93)
plt.show()
👇效果图如下

- 它围绕 0 上下波动,振幅标准化了
- 上穿 0,代表短期强势信号
- 下穿 0,可能是短期回落信号
是不是感觉比传统震荡指标"更稳重"一点?
做个策略测试 ------ 用它来做趋势跟踪交易!
我们设计一个非常简单的策略逻辑:
- 如果短周期 CyberOsc > 0 且 长周期 CyberOsc > 0,就全仓梭哈
- 如果任何一个 < 0,就平仓
第一步:先获取行情数据,然后根据上面的指标计算公式计算出cyber1和cyber2这2个指标。
python
df = ak.stock_zh_a_hist(symbol="股票代码",period='daily',start_date='20000101',adjust='hfq')
# 统一列名
df.rename(columns={
'日期': 'date',
'开盘': 'Open',
'最高': 'High',
'最低': 'Low',
'收盘': 'Close',
'成交量': 'Volume',
}, inplace=True)
# 设置时间索引,排序
df['date'] = pd.to_datetime(df['date'])
df.set_index('date', inplace=True)
df = df[['Open', 'High', 'Low', 'Close', 'Volume']]
df.sort_index(inplace=True)
df['cyber1'] = cyber_osc.cyber_oscillator(df['Close'], hp_len=30, lp_len=20)
df['cyber2'] = cyber_osc.cyber_oscillator(df['Close'], hp_len=250, lp_len=20)
# 补 openinterest 列(Backtrader 要求)
df["openinterest"] = 0
# 保留回测需要的字段
bt_df = df[["Open", "High", "Low", "Close", "Volume", "openinterest", "cyber1", "cyber2"]]
return bt_df
第二步:定义自定义数据类
python
class CustomData(bt.feeds.PandasData):
lines = ('cyber1', 'cyber2',)
params = (('cyber1', -1), ('cyber2', -1),)
第三步:策略逻辑
两个cyber都大于0就全仓干,小于0就平仓
python
class CyberOscStrategy(bt.Strategy):
def next(self):
if not self.position:
if self.data.cyber1[0] > 0 and self.data.cyber2[0] > 0:
cash = self.broker.getcash()
size = int(cash / self.data.close[0])
if size > 0:
self.buy(size=size)
else:
if self.data.cyber1[0] < 0 or self.data.cyber2[0] < 0:
self.close()
第三步:启动回测框架
python
# 获取数据
bt_df = get_hq().tail(500) # 截取最近500天的数据
# 创建回测引擎
cerebro = bt.Cerebro()
cerebro.addstrategy(CyberOscStrategy)
# 加载数据
data = CustomData(dataname=bt_df)
cerebro.adddata(data)
# 设置资金、手续费
cerebro.broker.setcash(100000.0)
cerebro.broker.setcommission(commission=0.001)
print(f"初始资金: {cerebro.broker.getvalue():.2f}")
cerebro.run()
print(f"回测结束资金: {cerebro.broker.getvalue():.2f}")
# 画图
cerebro.plot(style='candlestick')

初始资金: 100000.00 回测结束资金: 110194.57
500天收益达到了10.19%还不错!
这里只是抛砖引玉,想要把CyberOsc应用到真正的实盘策略还需要不断的打磨调整参数。
完整的代码花姐已经放到星球了,欢迎大家下载。
本策略仅作学术交流,回测结果不代表未来表现,市场有风险,决策需谨慎