[TOC]

Dieser Artikel istEine populärwissenschaftliche Einführung in die Wavelet-Transformation für den praktischen HandelDer Code ist eine vereinfachte Lehrversion (in der komplexe Schritte wie die mehrstufige Zerlegung, die Schwellenwert-Entrauschung und die inverse Transformationsrekonstruktion von Standard-Wavelets weggelassen werden), die nur die Kernideen beibehält:Mithilfe von Wavelet-Koeffizienten wird eine mehrskalige Glättung der Preise durchgeführt, um Trendinformationen zu extrahieren.Geeignet für Strategieentwicklung und schnelle Validierung, jedoch nicht für akademische Forschung oder wissenschaftliche Publikationen.
Wer auf Zhihu regelmäßig Finanz- und quantitative Themen durchstöbert, kennt dieses Szenario sicherlich:
Manche „Experten“ behaupten immer wieder:
Er versetzte alle in Erstaunen, als hätte er die Atomwaffe des quantitativen Handels gemeistert.
Aber Sie wollen, dass er Ihnen den Code zeigt?
„Dies… ist ein Geschäftsgeheimnis, und ich kann es nicht preisgeben.“
Bitten Sie ihn, das Prinzip zu erklären.
„Das… beinhaltet fortgeschrittene Mathematik, die Sie selbst dann nicht verstehen würden, wenn ich sie Ihnen erklären würde.“
Heute werden wir die von diesen „Zhihu-Experten“ häufig erwähnten Themen näher beleuchten, die praktischen Anwendungen der Wavelet-Transformation auf dem Finanzmarkt vorstellen und jedem helfen, ein korrektes Verständnis dieser Technologie zu entwickeln.
Stellen Sie sich vor, Sie hören ein Lied, aber die Aufnahme enthält Hintergrundgeräusche:
Originalaufnahme = menschliche Stimme + Hintergrundgeräusche + Rauschen
Die Wavelet-Transformation ist wie eineIntelligente Filter:
Wechsel zum Finanzmarkt:
Ursprünglicher Preis = Tatsächlicher Trend + Kurzfristige Schwankungen + Zufallsrauschen
Die Wavelet-Transformation kann Ihnen helfen:
Das Wesen der Wavelet-Transformation istZerlegen Sie das ursprüngliche Signal mithilfe eines spezifischen Satzes von „Basisfunktionen“ (Wavelets).。
Stellen Sie sich vor, Sie möchten das Aussehen einer Person beschreiben:
Im Bereich der Finanzpreise:
Ursprüngliche Preisreihe = Basisfunktion 1 × Gewicht 1 + Basisfunktion 2 × Gewicht 2 + … + Rauschen
Basisfunktionen sind die „Vorlagen“, die den Wavelet-Koeffizienten entsprechen.Unterschiedliche Wavelet-Typen (Haar, Daubechies, Mexican Hat usw.) verwenden unterschiedliche Vorlagen, genau wie unterschiedliche „Feature-Extraktoren“ zur Zerlegung von Preisen verwendet werden.
Die Wavelet-Transformation ist im Wesentlichen eine…Multiskalige Filterbank:
Hochfrequenzfilter → Erfasst schnelle Schwankungen (tägliches Rauschen, Tick-Schwankungen) Zwischenfrequenzfilter → Erfasst mittelfristige Trends (Frequenzbänder von wenigen Stunden bis zu wenigen Tagen). Niederfrequenzfilter → Erfassen langfristige Trends (wöchentliche und monatliche Trends).
Warum wird es „Wavelet“ genannt?
Das Problem bei der Verwendung von Sinuswellen zur Analyse von Finanzpreisen: Sinuswellen setzen voraus, dass sich das Signal periodisch wiederholt, aber Finanzmärkte tun dies nicht! BTC könnte heute um 10 % steigen und morgen um 8 % fallen, ohne jegliche Zyklizität.
Vorteile von Wavelets:LokalisierungsanalyseEs kann Ihnen sagen „Der Preistrend war am 20. Dezember 2025 zwischen 15 und 17 Uhr überwiegend aufwärtsgerichtet“, anstatt eine allgemeine Schlussfolgerung wie „Der Gesamtmarkt schwankte“ zu ziehen.
Die Wavelet-Transformation istReversibelDas ist sehr wichtig!
Ursprünglicher Preis —> Wavelet-Zerlegung —> Trendkomponente + Volatilitätskomponente + Rauschkomponente Trendkomponente + Volatilitätskomponente + Rauschkomponente —> Wavelet-Rekonstruktion —> Originalpreis
Refactoring-ProzessEs dient dazu, die verschiedenen Komponenten zu zerlegen.Selektiv wieder zusammenführen:
Trendkomponenten dürfen nur während der Rekonstruktion verwendet werden.
Nach der Zersetzung wurde Folgendes erhalten
Bei tatsächlichen Transaktionen gehen wir üblicherweise so vor:Rekonstruiere nur den niederfrequenten Teil(Trend) Die hochfrequenten Komponenten (Rauschen) werden direkt verworfen. Dies ist das Prinzip der Wavelet-„Rauschunterdrückung“.
Lassen wir die komplexen Integralformeln beiseite und erklären wir es in einfachen Worten:
Wavelet-Transformation = gewichteter Durchschnitt der Preisreihe unter Verwendung eines Satzes von “Wavelet-Koeffizienten”
Grundformel:
Glättungspreise[i] = Σ(ursprünglicher Preis)[i-j] × Wavelet-Koeffizienten[j]) / Σ(Wavelet-Koeffizienten)[j])
Filterperspektive:
Der Originalpreis wird durch einen Wavelet-Filter gefiltert → Komponenten unterschiedlicher Frequenzen werden “ausgewählt”.
Der Schlüssel istAuswahl der Wavelet-Koeffizienten:
Zum Beispiel:
Unter der Annahme, dass Sie Daubechies-4-Wavelets verwenden, lauten die Koeffizienten:[0.483, 0.837, 0.224, -0.129]:
Dieser Satz von Koeffizienten definiert einen Filter:
Die Wavelet-Transformation ist abgeschlossen, wenn Sie diesen Filter über die gesamte Preisreihe „schieben“. Jeder Schiebevorgang beinhaltet Berechnungen.Gewichteter Durchschnitt der Preise innerhalb des aktuellen FenstersDie Gewichte sind die Wavelet-Koeffizienten.
Warum kann es Signale “zerlegen”?
Denn es lässt sich mathematisch beweisen, dass:Jedes Signal kann als Linearkombination von Wavelet-Basisfunktionen dargestellt werden.So wie sich jede Farbe durch Mischen der drei RGB-Primärfarben erzeugen lässt, kann sich jede Kursreihe durch die Kombination von Wavelet-Basisfunktionen ableiten. Verschiedene Wavelet-Typen bieten unterschiedliche „Basisfunktionsbibliotheken“, die sich für verschiedene Arten der Signalanalyse eignen.
In Lehrbüchern zur Signalverarbeitung beinhaltet die Wavelet-Transformation typischerweise komplexe…Mehrstufige Zerlegung, Rekonstruktion und Schwellenwert-EntrauschungSchritte:
Vollständiger Workflow für die Wavelet-Analyse:
AberPraktische Anwendungen von FinanztransaktionenIn China muss es nicht so kompliziert sein. Denn:
1. Für den Handel ist lediglich die Trendrichtung erforderlich; eine perfekte Rekonstruktion ist nicht notwendig.
In der akademischen Forschung mag ein Rekonstruktionsfehler von unter 0,01 % erforderlich sein, im Handel reicht dies jedoch aus, um vorherzusagen, ob der Kurs steigen oder fallen wird. Selbst bei einem Rekonstruktionsfehler von 5 % kann die Strategie profitabel sein, solange die Trendrichtung korrekt ist.
2. Echtzeitanforderungen vereinfachen die Berechnungen.
Eine vollständige Wavelet-Zerlegung erfordert die rekursive Berechnung mehrerer Koeffizientenebenen, was im Hochfrequenzhandel zu Verzögerungen führen kann. Die direkte Faltung hingegen kann in Millisekunden abgeschlossen werden und erfüllt somit die Anforderungen des Live-Handels.
3. Die besonderen Merkmale von Finanzsignalen
Finanzpreise sind keine stabilen Signale und weisen keine strikte Zyklizität auf. Eine komplexe Frequenzzerlegung ist hier wenig aussagekräftig; eine einfache Trendbestimmung ist praktikabler.
Daher dieser ArtikelDie Essenz der Wavelet-Transformation herausarbeitenMit Fokus auf die praktischsten Aspekte der Finanzmärkte:
Kernvereinfachung 1: Nur Näherungskoeffizienten verwenden (niederfrequente Trends)
Traditionelle Wavelet-Zerlegung → Approximationskoeffizienten + Detailkoeffizienten (mehrschichtig) Diese Anwendung: Nur approximative Koeffizienten beibehalten → direkt den geglätteten Trend erhalten.
Kernvereinfachung 2: Direkte Faltung ohne Schwellenwertbildung (Entrauschung)
Traditionelle Wavelet-Zerlegung → Schwellenwertbildung der Detailkoeffizienten → Rekonstruktion Diese Anwendung: Direkte Faltung → um geglättete Preise zu erhalten
Kernvereinfachung 3: Randverarbeitung ignorieren
Traditionelle Wavelets erfordern eine Vorverarbeitung, wie zum Beispiel die symmetrische und periodische Erweiterung der Signalgrenzen. Diese Anwendung konzentriert sich nur auf den mittleren Abschnitt; Abweichungen an den Rändern sind akzeptabel.
Implementierungsmethode: Filterfaltung
def convolve(src, coeffs, step):
"""
核心算法:用小波系数对价格序列做加权平均
src: 价格序列 [100000, 101000, 99000, ...]
coeffs: 小波系数 [0.483, 0.837, 0.224, -0.129]
step: 采样步长(用于多层级)
"""
sum_val = 0.0 # 加权和
sum_w = 0.0 # 权重和
for i, weight in enumerate(coeffs):
idx = i * step
if idx < len(src):
sum_val += src[idx] * weight
sum_w += weight
return sum_val / sum_w # 归一化
Diese Funktion ist…Der Kern der Wavelet-Filter:
stepDie Parameter ermöglichen eine mehrstufige Glättung (Stufe 1/2/3…).Warum ist diese Vereinfachung sinnvoll?
Denn die grundlegende Voraussetzung für Transaktionen ist:Trends im Lärm erkennenDie Approximationskoeffizienten der Wavelet-Transformation sind selbst ein „Tiefpassfilter“ für das Signal, der niederfrequente Trendkomponenten erhält, was genau das ist, was wir brauchen.
Die vollständige Wavelet-Analyse ist zwar präziser, aber im Finanzhandel gilt Folgendes:
verwendenDie lokale Backtesting-Engine der Inventor Quantization (FMZ)-PlattformEs ist sehr praktisch, Daten zu erhalten!
'''backtest
start: 2025-12-17 00:00:00
end: 2025-12-23 08:00:00
period: 1h
basePeriod: 1h
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT","fee":[0,0]}]
'''
from fmz import *
task = VCtx(__doc__)
def main():
exchange.SetCurrency("BTC_USDT")
exchange.SetContractType("swap")
records = exchange.GetRecords(PERIOD_H1, 500)
return records
records = main()
Komplexe API-Integrationen oder Datenbereinigungen sind nicht erforderlich; standardisierte Candlestick-Daten können direkt abgerufen werden. Dadurch können wir die tatsächlichen Auswirkungen der sieben Wavelet-Typen schnell überprüfen, anstatt uns in der Datenverarbeitung zu verlieren.
Durch den Vergleich der Leistungsfähigkeit von sieben gängigen Wavelet-Typen (Haar, Daubechies 4, Symlet 4, Biorthogonal 3.3, Mexican Hat, Morlet und Discrete Meyer) anhand von Kryptowährungspreisen wird die folgende visuelle Darstellung gegeben:
Der Fokus liegt nicht auf der Strenge der mathematischen Herleitung, sondern auf dem visuellen Vergleich der praktischen Ergebnisse.Dies hilft Händlern, ein intuitives Verständnis zu entwickeln und den Wavelet-Typ auszuwählen, der zu ihrer Strategie passt.
Die Haar-Wavelet-Welle ist die einfachste Art der Wavelet-Welle und besteht nur aus zwei Koeffizienten:[0.5, 0.5]Im Wesentlichen handelt es sich um einen einfachen Durchschnitt zweier aufeinanderfolgender Preise.
Kerncode:
coeffs = [0.5, 0.5]
# 对价格序列 [100000, 101000, 99000, 102000, 98000] 处理
def smooth(prices, i):
return (prices[i] * 0.5 + prices[i-1] * 0.5) / 1.0
# 结果:[100000, 100500, 100000, 100500, 100000]
Wie Sie sehen, stabilisiert sich der ursprünglich stark schwankende Preis (zwischen 99.000 und 102.000) nach der Haar-Transformation. Dies ist der Effekt der Wavelet-Entrauschung – sie glättet kurzfristige, heftige Schwankungen und ermöglicht so die Darstellung eines gleichmäßigeren Preistrends.

Daubechies 4 (kurz db4) ist eine der am häufigsten verwendeten Wavelets im Ingenieurwesen. Ihre Koeffizienten sind:[0.483, 0.837, 0.224, -0.129]Beachten Sie, dass der letzte Koeffizient…negative ZahlDas macht es einzigartig.
Kerncode:
coeffs = [0.483, 0.837, 0.224, -0.129]
# 处理第i个价格点
def smooth(prices, i):
weighted_sum = (prices[i] * 0.483 + # 当前价格
prices[i-1] * 0.837 + # 前1根,权重最大!
prices[i-2] * 0.224 + # 前2根
prices[i-3] * (-0.129)) # 前3根,负权重
weight_sum = 0.483 + 0.837 + 0.224 + (-0.129) # = 1.415
return weighted_sum / weight_sum
# 示例:smooth([100000, 101000, 99000, 102000], 3) ≈ 100251
Hauptmerkmale:Das Gewicht des vorherigen Candlesticks (0,837) ist größer als das des aktuellen Preises (0,483)! Das bedeutet, dass db4 dem „gerade erreichten Preis“ mehr Gewicht beimisst und der negative Gewichtungskoeffizient den früheren Preis ausgleicht, wodurch die Glättung weiter verstärkt wird.

Symlet 4 ist eine verbesserte Version von Daubechies mit dem Ziel einer höheren Symmetrie. Koeffizienten:[-0.076, -0.030, 0.498, 0.804, 0.298, -0.099, -0.013, 0.032]。
Kerncode:
coeffs = [-0.076, -0.030, 0.498, 0.804, 0.298, -0.099, -0.013, 0.032]
# 向前看8根K线
def smooth(prices, i):
weighted_sum = sum(prices[i-j] * coeffs[j] for j in range(8))
weight_sum = sum(coeffs)
return weighted_sum / weight_sum
# 平滑效果比Haar和db4都强,但反应速度更慢
Hauptmerkmale:Eine Fensterlänge von 8 Kerzen ermöglicht ein längeres „Gedächtnis“ für die Preise. Eine echte Trendumkehr ist auf einer glatten Kurve möglicherweise erst nach Ablauf von 8 Kerzen sichtbar.

Biorthogonal 3.3 (abgekürzt bior3.3) ist ein perfekt symmetrisches Wavelet mit folgenden Koeffizienten:[-0.066, 0.283, 0.637, 0.283, -0.066]。
Kerncode:
coeffs = [-0.066, 0.283, 0.637, 0.283, -0.066]
# ↑ 中心↑ ↑
# 完全对称的两端
# 处理中间价格点
def smooth(prices, i):
# 实际应用:只向前看,不使用未来数据
weighted_sum = (prices[i-4] * (-0.066) + # 前4根
prices[i-3] * 0.283 + # 前3根
prices[i-2] * 0.637 + # 前2根,权重最大
prices[i-1] * 0.283 + # 前1根
prices[i] * (-0.066)) # 当前
weight_sum = sum(coeffs) # = 1.071
return weighted_sum / weight_sum
Hauptmerkmale:Durch die Symmetrie wird sichergestellt, dass es keine „Phasenverzerrung“ gibt – die geglättete Kurve verschiebt sich nicht unerklärlicherweise nach links oder rechts.

Mexikanischer Hut (auch Ricker-Wavelet genannt) Koeffizienten:[-0.1, 0.0, 0.4, 0.8, 0.4, 0.0, -0.1]Es hat die Form eines mexikanischen Sombreros.
Kerncode:
coeffs = [-0.1, 0.0, 0.4, 0.8, 0.4, 0.0, -0.1]
# 负值 零 正值 最大 正值 零 负值
# ↓ ↓
# "惩罚"两端,增强拐点检测能力
def smooth(prices, i):
weighted_sum = (prices[i-6] * (-0.1) + # 左3,负权重
prices[i-5] * 0.0 + # 左2
prices[i-4] * 0.4 + # 左1
prices[i-3] * 0.8 + # 中心,权重最大
prices[i-2] * 0.4 + # 右1
prices[i-1] * 0.0 + # 右2
prices[i] * (-0.1)) # 右3,负权重
weight_sum = sum(coeffs)
return weighted_sum / weight_sum
Hauptmerkmale:Durch seine Struktur „groß in der Mitte, negativ an beiden Enden“ eignet es sich besonders gut zur Detektion.WendepunktDer entscheidende Moment, in dem sich die Preise von einem Aufwärtstrend in einen Abwärtstrend umkehren (oder umgekehrt). Der negative Gewichtungskoeffizient „bestraft“ weit zurückliegende Preise und erfasst Trendwechsel so schnell.

Die Morlet-Wavelet-Transformation basiert auf einer Gaußschen (Normal-)Verteilung mit folgenden Koeffizienten:[0.0625, 0.25, 0.375, 0.25, 0.0625]。
Kerncode:
coeffs = [0.0625, 0.25, 0.375, 0.25, 0.0625]
# ↓ ↓ ↓中心 ↓ ↓
# 远端 近端 最高 近端 远端
# 完美的高斯钟形曲线
def smooth(prices, i):
weighted_sum = (prices[i-4] * 0.0625 + # 左2,6.25%
prices[i-3] * 0.25 + # 左1,25%
prices[i-2] * 0.375 + # 中心,37.5%
prices[i-1] * 0.25 + # 右1,25%
prices[i] * 0.0625) # 右2,6.25%
# 权重和正好 = 1.0,无需除法
return weighted_sum
Hauptmerkmale:Diese Wavelet-Formel ist die sanfteste aller Varianten, da sie keine negativen Gewichtungen aufweist und alle Preise sanft in die Berechnung einbezieht. Die resultierende Kurve ist extrem glatt, reagiert aber langsamer – plötzliche Preisänderungen werden unter Umständen erst nach mehreren Candlesticks sichtbar.

Die diskrete Meyer-Wavelet-Transformation ist die komplexeste Wavelet-Transformation mit folgenden Koeffizienten:[-0.015, -0.025, 0.0, 0.28, 0.52, 0.28, 0.0, -0.025, -0.015]。
Kerncode:
coeffs = [-0.015, -0.025, 0.0, 0.28, 0.52, 0.28, 0.0, -0.025, -0.015]
# ↑ ↑ ↑ ↑中心↑ ↑ ↑ ↑
# 完全对称,中心权重超过50%
def smooth(prices, i):
# 向前看9根K线
weighted_sum = sum(prices[i-j] * coeffs[j] for j in range(9))
weight_sum = sum(coeffs) # = 1.0
return weighted_sum
# 注意:第4根之前的K线权重是0.52,超过50%!
# 实际上在告诉你"4根K线之前的中期趋势"
Hauptmerkmale:Es verfügt über die meisten Koeffizienten (9), die längste historische Datenbasis und den stärksten Glättungseffekt. Es eignet sich zur Ermittlung von Wochentrends, weist jedoch eine erhebliche Verzögerung auf – selbst wenn der Kurs um 10 % gefallen ist, kann die Kurve weiterhin einen „weiteren Anstieg“ anzeigen.

Nach der Betrachtung der sieben Wavelet-Typen sollte Ihnen ein Muster aufgefallen sein:
Mehr Koeffizienten = weitere Sichtbarkeit = stärkere Glättung = größere Latenz
Haar (2 Koeffizienten) → Nur 1 Balken betrachten → Nahezu nicht glatt Daubechies 4 (4 Stück) → Siehe 3 vorher → Leicht glatt Mexikanischer Hut (7) → Siehe 6 vorher → Mäßige Glättung Diskretes Meyer (9) → Vor der Anzeige von 8 Balken → Starke Glättung
Negative Gewichtungen erhöhen die Sensitivität und erleichtern das Erkennen von Veränderungen.
Haar/Morlet (keine negativen Gewichte) → Sanft und geschmeidig, unempfindlich Mexikanischer Hut (negativ an beiden Enden) → Sensitiv gegenüber Wendepunkten Daubechies 4 (negativ) → Sensitiv gegenüber Trendänderungen
Die Rolle der Symmetrie = keine Verzerrung = Erhalt der ursprünglichen Form
Asymmetrie (Daubechies) → Kann nach links/rechts verschoben werden Symmetrie (Biorthogonal/Meyer) → Beibehaltung der zentralen Position
Die Wavelet-Transformation lässt sich rekursiv anwenden, ähnlich wie ineinander verschachtelte Puppen. Die erste Anwendung wird als Ebene 1 bezeichnet, die erneute Anwendung auf das Ergebnis von Ebene 1 als Ebene 2 usw.
Die auf verschiedenen Ebenen betrachteten Zeitskalen:
Angenommen, wir verwenden 1-Stunden-Kerzencharts für den BTC-Handel:
Stufe 1 → Kurzfristige Schwankungen über 2-4 Stunden beobachten Stufe 2 → Beobachten Sie den Trend über 4-8 Stunden Stufe 3 → Beobachten Sie den mittelfristigen Trend über 1-2 Tage (gängige Strategie) Stufe 4 → Beobachten Sie die Preisspanne der letzten 2-4 Tage. Stufe 5 → Beobachten Sie die wichtigsten Trends über 4-8 Tage
Vergleich der tatsächlichen Ergebnisse:
Ursprünglicher BTC-Preis (1-Stunden-Chart):99500, 99800, 99200, 100200, 99800, 100500, 100100, ...
Verarbeitungsstufe 1: 99600, 99650, 99500, 99900, 99950, 100200, 100250, … (Etwas geglättet, aber Schwankungen sind noch sichtbar)
Verarbeitungsstufe 3: 99620, 99650, 99700, 99800, 99950, 100100, 100200, … (Glätten, was einen mittelfristigen Trend andeutet)
Verarbeitungsstufe 5: 99630, 99640, 99660, 99700, 99760, 99840, 99930, … (Extrem glatt, zeigt nur die allgemeine Richtung an)

Das Auswahlprinzip ist einfach: Verwenden Sie das entsprechende Level basierend auf Ihrer Haltedauer.
15-Minuten-Scalping → Level 1-2
Intraday-Handel → Level 2-3
Mach ein paar Tage Swing → Level 3-4
Langfristige Trendanalyse → Stufe 4-5
Die Anwendung der Wavelet-Transformation im Trading ist sehr direkt: Anhand der geglätteten Kurskurve lässt sich die Trendrichtung bestimmen. Handel erfolgt bei einem Trendwechsel. Liegt der geglättete Schlusskurs über dem vorherigen, deutet dies auf einen Aufwärtstrend hin – Long-Position. Liegt er hingegen darunter, signalisiert dies einen Abwärtstrend – Position schließen oder Short-Position eröffnen. Diese Logik ist effektiv, da Wavelets kurzfristige, zufällige Schwankungen herausfiltern. So bleibt ein „Aufwärts“- oder „Abwärts“-Signal mit hoher Wahrscheinlichkeit für einen tatsächlichen Trendwechsel übrig, anstatt eines durch Rauschen verursachten Fehlsignals.
# 执行小波变换
transformed = transformer.transform_ohlc(df)
# 获取最近两根K线的平滑收盘价
w_close_current = transformed['w_close'].values[-1] # 当前平滑收盘价
w_close_prev = transformed['w_close'].values[-2] # 前一根平滑收盘价
# 判断趋势方向
signal = 0
if w_close_current > w_close_prev:
signal = 1 # 平滑价格向上 → 做多
elif w_close_current < w_close_prev:
signal = -1 # 平滑价格向下 → 做空
# 获取账户信息
account = exchange.GetAccount()
ticker = exchange.GetTicker()
if not account or not ticker:
Log("[Warning] Failed to get account/ticker info")
Sleep(5000)
continue
current_price = ticker['Last']
Log(f"[Price] 原始: {df['Close'].values[-1]:.2f}, "
f"平滑当前: {w_close_current:.2f}, 平滑前值: {w_close_prev:.2f}")
Log(f"[Trend] {'↑ 向上' if signal == 1 else '↓ 向下' if signal == -1 else '→ 横盘'}")
# 执行交易逻辑
if signal == 1 and position != 1:
# 平滑价格向上 → 做多
Log(f"[信号] 趋势向上,开多 @ {current_price:.2f}")
if position == -1:
# 先平空仓
exchange.SetDirection("closesell")
exchange.Buy(current_price, 1)
Log(f"[平仓] 平空仓")
# 开多仓
exchange.SetDirection("buy")
exchange.Buy(current_price, 1)
Log(f"[开仓] 开多仓")
position = 1
elif signal == -1 and position != -1:
# 平滑价格向下 → 做空
Log(f"[信号] 趋势向下,开空 @ {current_price:.2f}")
if position == 1:
# 先平多仓
exchange.SetDirection("closebuy")
exchange.Sell(current_price, 1)
Log(f"[平仓] 平多仓")
# 开空仓
exchange.SetDirection("sell")
exchange.Sell(current_price, 1)
Log(f"[开仓] 开空仓")
position = -1
else:
Log(f"[持仓] 当前{'多头' if position == 1 else '空头' if position == -1 else '空仓'},无需操作")

In der Praxis ist es natürlich nicht ganz so einfach. Sie können mehrere Wavelet-Ebenen gleichzeitig nutzen, beispielsweise Ebene 2 für den kurzfristigen und Ebene 4 für den langfristigen Trend. Eröffnen Sie eine Position nur, wenn sich beide in dieselbe Richtung bewegen. Dadurch reduzieren Sie Fehlsignale deutlich. Sie können auch weitere Filterbedingungen hinzufügen, wie z. B. ein erhöhtes Handelsvolumen, eine ausreichend hohe Volatilität oder einen Kursausbruch über ein wichtiges Niveau. All dies kann die Trefferquote verbessern. Stop-Loss-Orders lassen sich dynamisch anhand der Wavelet-geglätteten Kursschwankungsbreite festlegen. Beispielsweise können Sie einen Stop-Loss auslösen, wenn der Kurs unter den geglätteten Kurs abzüglich des Zweifachen des ATR fällt. Beim Positionsmanagement gilt: Je deutlicher der Trend (je steiler die Steigung des geglätteten Kurses), desto größer die Positionsgröße. Ist der Trend unklar, wählen Sie eine kleinere Position oder bleiben Sie abwartend.
Die Grundidee bleibt jedoch dieselbe: Mithilfe von Wavelets werden verrauschte Kurse in klare Trends umgewandelt, auf deren Grundlage dann Schlussfolgerungen gezogen werden. Dies ist wesentlich zuverlässiger als die direkte Betrachtung der Kursbewegungen im ursprünglichen Candlestick-Chart, da dieser beispielsweise heute um 3 % steigen, morgen um 2 % fallen und übermorgen um 4 % steigen könnte. Man kann schlichtweg nicht erkennen, ob es sich um einen Trend oder eine Schwankung handelt. Die mittels Wavelets verarbeitete Kurve zeigt hingegen an: „Der Gesamttrend in diesem Zeitraum ist aufwärtsgerichtet, auch wenn es zwischenzeitlich Schwankungen gibt.“
Hinsichtlich praktischer Glättungseffekte kann die Wavelet-Transformation in der Finanzdatenverarbeitung durchaus eine Rolle spielen: Sie kann kurzfristiges Rauschen herausfiltern und dazu beitragen, relativ klare Trendinformationen zu extrahieren. Allerdings weist diese Technik auch erhebliche Einschränkungen auf –Das Problem der Verzögerung lässt sich nicht gänzlich vermeiden.Allerdings kann sie nur historische Daten verarbeiten und keine zukünftigen Trends vorhersagen. Darüber hinaus ist die Wirkung der Wavelet-Transformation allein relativ begrenzt; sie muss mit anderen Analysemethoden und Risikokontrollmaßnahmen kombiniert werden, um ein vollständiges Handelssystem zu entwickeln.
Der Hauptgrund für diese Einschränkung liegt in der einzigartigen Natur der Finanzmärkte. In traditionellen Bereichen der Signalverarbeitung wie Spracherkennung und Bildverarbeitung sind die Rauscheigenschaften relativ stabil, und Signalmuster neigen zur Wiederholung. Daher kann die Wavelet-Transformation Signale effektiv vom Rauschen trennen. Finanzmärkte verhalten sich jedoch völlig anders: Schwankungen, die heute als „Rauschen“ gelten, können morgen zu „Signalen“ werden, die Marktveränderungen widerspiegeln; analytische Modelle, die heute effektiv sind, können in Zukunft unwirksam werden.Der Markt selbst ist nicht stationär und unterliegt dynamischen Veränderungen.Bei der Wavelet-Transformation gibt es keine unveränderlichen Gesetze, weshalb die Anwendung der Wavelet-Transformation im Finanzbereich flexibel an das jeweilige Marktumfeld angepasst werden muss.
Wenn Sie jemanden sehen, der die tatsächlichen Auswirkungen der Wavelet- und Fourier-Transformation übertreibt, stellen Sie folgende Fragen: Welcher Wavelet-Typ wurde verwendet? Auf welcher Grundlage wurde dieser Typ und nicht andere gewählt? Wie wurde das Glättungsniveau festgelegt? Gibt es entsprechende Backtesting-Ergebnisse und Verfahren zur Parameterauswahl?Wer über echtes Fachwissen verfügt, kann diese wichtigen technischen Details klar erläutern.
Auf der Grundlage unseres begrenzten Wissens haben wir diese praktische Untersuchung durchgeführt.Die Kernidee besteht darin, die Anwendungskonzepte der Wavelet-Transformation auf einfache und leicht verständliche Weise zu vermitteln.Dieser Artikel soll Lesern ein grundlegendes Verständnis dieser Technologie vermitteln. Wir schätzen die Expertise quantitativer Forscher auf diesem Gebiet sehr. Sollten Sie Experte auf diesem Gebiet sein, bitten wir Sie, uns auf etwaige Schwächen des Artikels hinzuweisen – beispielsweise hinsichtlich der theoretischen Grundlagen für die Wavelet-Parameterwahl, Optimierungsmethoden für Multiskalenkombinationen und Implementierungswege für die adaptive Wavelet-Auswahl. Wir nehmen Ihre Anregungen dankend an und werden den Inhalt kontinuierlich verbessern.
Plotfunktion: Angewendet in der lokalen Backtesting-Engine des Erfinders.
'''backtest
start: 2025-12-17 00:00:00
end: 2025-12-23 08:00:00
period: 1h
basePeriod: 1h
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT","fee":[0,0]}]
'''
from fmz import *
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle
task = VCtx(__doc__)
# ==================== 小波系数库 ====================
class WaveletCoefficients:
"""Wavelet Coefficients Definition"""
@staticmethod
def get_coeffs(wavelet_name):
"""Get coefficients for different wavelet types"""
coeffs = {
"Haar": [0.5, 0.5],
"Daubechies 4": [
0.48296291314453414,
0.8365163037378079,
0.22414386804201339,
-0.12940952255126037
],
"Symlet 4": [
-0.05357, -0.02096, 0.35238,
0.56833, 0.21062, -0.07007,
-0.01941, 0.03268
],
"Biorthogonal 3.3": [
-0.06629, 0.28289, 0.63678,
0.28289, -0.06629
],
"Mexican Hat (Ricker)": [
-0.1, 0.0, 0.4, 0.8, 0.4, 0.0, -0.1
],
"Morlet (Gaussian)": [
0.0625, 0.25, 0.375, 0.25, 0.0625
],
"Discrete Meyer (Dmey)": [
-0.015, -0.025, 0.0,
0.28, 0.52, 0.28,
0.0, -0.025, -0.015
]
}
return coeffs.get(wavelet_name, coeffs["Mexican Hat (Ricker)"])
# ==================== 小波变换引擎 ====================
class WaveletTransform:
"""Wavelet Transform Engine"""
def __init__(self, wavelet_type="Mexican Hat (Ricker)", smoothing_level=3):
self.wavelet_type = wavelet_type
self.smoothing_level = smoothing_level
self.coeffs = WaveletCoefficients.get_coeffs(wavelet_type)
def convolve(self, src, coeffs, step):
"""
Convolution operation - Core algorithm
Args:
src: Source data sequence
coeffs: Wavelet coefficients
step: Sampling step
Returns:
Convolved value
"""
sum_val = 0.0
sum_w = 0.0
for i, weight in enumerate(coeffs):
idx = i * step
if idx < len(src):
val = src[idx]
sum_val += val * weight
sum_w += weight
# Normalization - Critical fix
return sum_val / sum_w if sum_w != 0 else sum_val
def calc_level(self, data, target_level):
"""
Calculate wavelet transform for specified level
Args:
data: Original data array
target_level: Target smoothing level
Returns:
Transformed data array
"""
result = []
coeffs = self.coeffs
for i in range(len(data)):
# Get data from current position backwards
src = data[max(0, i - 50):i + 1][::-1]
# Level 1
val = self.convolve(src, coeffs, 1)
# Level 2
if target_level >= 2:
src_temp = [val] + [self.convolve(data[max(0, j - 50):j + 1][::-1], coeffs, 1)
for j in range(max(0, i - 10), i)][::-1]
val = self.convolve(src_temp, coeffs, 2)
# Level 3
if target_level >= 3:
val = self.convolve([val] * len(coeffs), coeffs, 4)
# Level 4+
if target_level >= 4:
val = self.convolve([val] * len(coeffs), coeffs, 8)
result.append(val)
return np.array(result)
def transform_ohlc(self, df):
"""
Perform wavelet transform on OHLC data
Args:
df: DataFrame with Open/High/Low/Close
Returns:
Transformed DataFrame
"""
result_df = df.copy()
# Transform each price series
result_df['w_open'] = self.calc_level(df['Open'].values, self.smoothing_level)
result_df['w_high'] = self.calc_level(df['High'].values, self.smoothing_level)
result_df['w_low'] = self.calc_level(df['Low'].values, self.smoothing_level)
result_df['w_close'] = self.calc_level(df['Close'].values, self.smoothing_level)
# Reconstruct logically consistent candlesticks
result_df['real_high'] = result_df[['w_high', 'w_low', 'w_open', 'w_close']].max(axis=1)
result_df['real_low'] = result_df[['w_high', 'w_low', 'w_open', 'w_close']].min(axis=1)
return result_df
# ==================== K线图可视化工具 ====================
class WaveletCandlestickVisualizer:
"""Wavelet Candlestick Visualization"""
@staticmethod
def plot_single_wavelet(df, wavelet_type, smoothing_level=3, n_bars=200):
"""
Plot single wavelet type comparison
Args:
df: Original candlestick data
wavelet_type: Wavelet type
smoothing_level: Smoothing level
n_bars: Number of bars to display
"""
# Take only last n_bars
df_plot = df.iloc[-n_bars:].copy()
# Create figure
fig, ax = plt.subplots(figsize=(20, 8))
# Perform wavelet transform
transformer = WaveletTransform(wavelet_type, smoothing_level)
transformed = transformer.transform_ohlc(df)
transformed_plot = transformed.iloc[-n_bars:].copy()
# Draw original candlesticks (gray background)
WaveletCandlestickVisualizer._draw_candlesticks(
ax, df_plot,
color_up='lightgray',
color_down='lightgray',
alpha=0.3,
label='Original Candles'
)
# Draw wavelet smoothed candlesticks
WaveletCandlestickVisualizer._draw_candlesticks(
ax, transformed_plot,
use_wavelet=True,
color_up='#26A69A', # Green
color_down='#EF5350', # Red
alpha=0.9,
linewidth=1.2,
label=f'{wavelet_type} Smoothed (Level {smoothing_level})'
)
# Set title and labels
ax.set_title(f'{wavelet_type} Wavelet (Level {smoothing_level}) - Candlestick Comparison',
fontsize=16, fontweight='bold', pad=20)
ax.set_ylabel('Price (USDT)', fontsize=13)
ax.set_xlabel('Time', fontsize=13)
ax.grid(True, alpha=0.2, linestyle='--')
ax.legend(loc='upper left', fontsize=12)
# Format x-axis
ax.set_xlim(-1, len(df_plot))
ax.set_xticks(range(0, len(df_plot), max(1, len(df_plot) // 10)))
ax.set_xticklabels([df_plot.index[i].strftime('%m-%d %H:%M')
for i in range(0, len(df_plot), max(1, len(df_plot) // 10))],
rotation=45, ha='right')
plt.tight_layout()
plt.show()
return fig
@staticmethod
def plot_single_level(df, wavelet_type, level, n_bars=200):
"""
Plot single smoothing level
Args:
df: Original candlestick data
wavelet_type: Wavelet type
level: Smoothing level
n_bars: Number of bars to display
"""
# Take only last n_bars
df_plot = df.iloc[-n_bars:].copy()
# Create figure
fig, ax = plt.subplots(figsize=(20, 8))
# Perform wavelet transform
transformer = WaveletTransform(wavelet_type, level)
transformed = transformer.transform_ohlc(df)
transformed_plot = transformed.iloc[-n_bars:].copy()
# Draw original candlesticks
WaveletCandlestickVisualizer._draw_candlesticks(
ax, df_plot,
color_up='lightgray',
color_down='lightgray',
alpha=0.3,
label='Original Candles'
)
# Draw wavelet smoothed candlesticks
WaveletCandlestickVisualizer._draw_candlesticks(
ax, transformed_plot,
use_wavelet=True,
color_up='#26A69A',
color_down='#EF5350',
alpha=0.9,
linewidth=1.2,
label=f'Level {level} Smoothed'
)
# Set title and labels
ax.set_title(f'{wavelet_type} - Smoothing Level {level} Effect',
fontsize=16, fontweight='bold', pad=20)
ax.set_ylabel('Price (USDT)', fontsize=13)
ax.set_xlabel('Time', fontsize=13)
ax.grid(True, alpha=0.2, linestyle='--')
ax.legend(loc='upper left', fontsize=12)
# Format x-axis
ax.set_xlim(-1, len(df_plot))
ax.set_xticks(range(0, len(df_plot), max(1, len(df_plot) // 10)))
ax.set_xticklabels([df_plot.index[i].strftime('%m-%d %H:%M')
for i in range(0, len(df_plot), max(1, len(df_plot) // 10))],
rotation=45, ha='right')
plt.tight_layout()
plt.show()
return fig
@staticmethod
def _draw_candlesticks(ax, df, use_wavelet=False, color_up='green',
color_down='red', alpha=1.0, linewidth=1.0, label=''):
"""
Draw candlestick chart
Args:
ax: Matplotlib axis
df: Data DataFrame
use_wavelet: Whether to use wavelet data
color_up: Up color
color_down: Down color
alpha: Transparency
linewidth: Line width
label: Legend label
"""
if use_wavelet:
opens = df['w_open'].values
highs = df['real_high'].values
lows = df['real_low'].values
closes = df['w_close'].values
else:
opens = df['Open'].values
highs = df['High'].values
lows = df['Low'].values
closes = df['Close'].values
for i in range(len(df)):
x = i
open_price = opens[i]
high_price = highs[i]
low_price = lows[i]
close_price = closes[i]
color = color_up if close_price >= open_price else color_down
# Draw wick
ax.plot([x, x], [low_price, high_price],
color=color, linewidth=linewidth, alpha=alpha)
# Draw body
height = abs(close_price - open_price)
bottom = min(open_price, close_price)
rect = Rectangle((x - 0.3, bottom), 0.6, height,
facecolor=color, edgecolor=color,
alpha=alpha, linewidth=linewidth)
ax.add_patch(rect)
# Add legend (only once)
if label:
ax.plot([], [], color=color_up, linewidth=3, alpha=alpha, label=label)
# ==================== 主函数 ====================
def main():
"""Main execution flow"""
exchange.SetCurrency("BTC_USDT")
exchange.SetContractType("swap")
# Get candlestick data
records = exchange.GetRecords(PERIOD_H1, 500)
# Convert to DataFrame
df = pd.DataFrame(records, columns=['Time', 'Open', 'High', 'Low', 'Close', 'Volume'])
df['Time'] = pd.to_datetime(df['Time'], unit='ms')
df.set_index('Time', inplace=True)
print(f"Data loaded: {len(df)} bars")
print(f"Time range: {df.index[0]} to {df.index[-1]}")
print(f"Price range: ${df['Low'].min():.2f} - ${df['High'].max():.2f}")
return df
# ==================== 执行绘图 ====================
try:
# Get candlestick data
kline = main()
print("\n" + "="*70)
print("Generating Wavelet Candlestick Charts (Each in Separate Window)...")
print("="*70)
# ========== Chart Series 1: Different Wavelet Types ==========
print("\n[Series 1] Comparing Different Wavelet Types")
print("-" * 70)
wavelet_types = [
"Haar",
"Daubechies 4",
"Symlet 4",
"Biorthogonal 3.3",
"Mexican Hat (Ricker)",
"Morlet (Gaussian)",
"Discrete Meyer (Dmey)" # ✅ 添加了 Discrete Meyer
]
for i, wavelet_type in enumerate(wavelet_types, 1):
print(f" Chart {i}/{len(wavelet_types)}: {wavelet_type}")
fig = WaveletCandlestickVisualizer.plot_single_wavelet(
kline,
wavelet_type=wavelet_type,
smoothing_level=3,
n_bars=150
)
# ========== Chart Series 2: Different Smoothing Levels ==========
print("\n[Series 2] Comparing Different Smoothing Levels")
print("-" * 70)
levels = [1, 2, 3, 4, 5]
for i, level in enumerate(levels, 1):
print(f" Chart {i}/5: Level {level}")
fig = WaveletCandlestickVisualizer.plot_single_level(
kline,
wavelet_type="Mexican Hat (Ricker)",
level=level,
n_bars=150
)
print("\n" + "="*70)
print("All charts generated successfully!")
print(f"Total charts: {len(wavelet_types) + len(levels)} ({len(wavelet_types)} wavelets + {len(levels)} levels)")
print("="*70)
except Exception as e:
print(f"Error: {str(e)}")
import traceback
print(traceback.format_exc())
finally:
print("\nStrategy testing completed.")
Transaktionsfunktionen: Angewendet auf der Inventors-Plattform
'''backtest
start: 2025-01-17 00:00:00
end: 2025-12-23 08:00:00
period: 1h
basePeriod: 1h
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT","fee":[0,0]}]
'''
import numpy as np
import pandas as pd
# ==================== 小波系数库 ====================
class WaveletCoefficients:
"""与上部分函数一致"""
# ==================== 小波变换引擎 ====================
class WaveletTransform:
"""与上部分函数一致"""
def main():
"""小波交易主函数 - 基于平滑价格趋势"""
# ========== 配置参数 ==========
WAVELET_TYPE = "Mexican Hat (Ricker)" # 小波类型
SMOOTHING_LEVEL = 1 # 平滑阶数
# 初始化
exchange.SetCurrency("BTC_USDT")
exchange.SetContractType("swap")
Log(f"=" * 70)
Log(f"Wavelet Trend Following Strategy")
Log(f"Wavelet: {WAVELET_TYPE}, Level: {SMOOTHING_LEVEL}")
Log(f"Logic: 平滑收盘价向上→做多, 平滑收盘价向下→做空")
Log(f"=" * 70)
# 初始化小波变换器
transformer = WaveletTransform(WAVELET_TYPE, SMOOTHING_LEVEL)
# 持仓状态
position = 0 # 0: 无持仓, 1: 多头, -1: 空头
while True:
# 获取K线数据
records = exchange.GetRecords(PERIOD_H1, 500)
if not records:
Log("[Warning] Failed to get kline data")
Sleep(5000)
continue
df = pd.DataFrame(records, columns=['Time', 'Open', 'High', 'Low', 'Close', 'Volume'])
df['Time'] = pd.to_datetime(df['Time'], unit='ms')
df.set_index('Time', inplace=True)
# 执行小波变换
transformed = transformer.transform_ohlc(df)
# 获取最近两根K线的平滑收盘价
w_close_current = transformed['w_close'].values[-1] # 当前平滑收盘价
w_close_prev = transformed['w_close'].values[-2] # 前一根平滑收盘价
# 判断趋势方向
signal = 0
if w_close_current > w_close_prev:
signal = 1 # 平滑价格向上 → 做多
elif w_close_current < w_close_prev:
signal = -1 # 平滑价格向下 → 做空
# 获取账户信息
account = exchange.GetAccount()
ticker = exchange.GetTicker()
if not account or not ticker:
Log("[Warning] Failed to get account/ticker info")
Sleep(5000)
continue
current_price = ticker['Last']
Log(f"[Price] 原始: {df['Close'].values[-1]:.2f}, "
f"平滑当前: {w_close_current:.2f}, 平滑前值: {w_close_prev:.2f}")
Log(f"[Trend] {'↑ 向上' if signal == 1 else '↓ 向下' if signal == -1 else '→ 横盘'}")
# 执行交易逻辑
if signal == 1 and position != 1:
# 平滑价格向上 → 做多
Log(f"[信号] 趋势向上,开多 @ {current_price:.2f}")
if position == -1:
# 先平空仓
exchange.SetDirection("closesell")
exchange.Buy(current_price, 1)
Log(f"[平仓] 平空仓")
# 开多仓
exchange.SetDirection("buy")
exchange.Buy(current_price, 1)
Log(f"[开仓] 开多仓")
position = 1
elif signal == -1 and position != -1:
# 平滑价格向下 → 做空
Log(f"[信号] 趋势向下,开空 @ {current_price:.2f}")
if position == 1:
# 先平多仓
exchange.SetDirection("closebuy")
exchange.Sell(current_price, 1)
Log(f"[平仓] 平多仓")
# 开空仓
exchange.SetDirection("sell")
exchange.Sell(current_price, 1)
Log(f"[开仓] 开空仓")
position = -1
else:
Log(f"[持仓] 当前{'多头' if position == 1 else '空头' if position == -1 else '空仓'},无需操作")
Log(f"[账户] 余额: {account['Balance']:.2f}, 权益: {account['Equity']:.2f}")
Log("-" * 70)
Sleep(60000 * 60)