[TOC]

Artikel ini adalahSains Popular tentang Transformasi Wavelet untuk Perdagangan PraktikalKod ini merupakan versi pengajaran yang dipermudahkan (mengecualikan langkah-langkah kompleks seperti penguraian berbilang peringkat, penyahbisingan ambang dan pembinaan semula transformasi songsang bagi wavelet piawai), hanya mengekalkan idea teras:Gunakan pekali wavelet untuk melakukan pelicinan berbilang skala pada harga bagi mendapatkan maklumat trend.Sesuai untuk pembangunan strategi dan pengesahan pantas, tetapi bukan untuk penyelidikan akademik atau penerbitan kertas kerja.
Mereka yang kerap melayari topik kewangan dan kuantitatif di Zhihu pasti pernah melihat senario ini:
Sesetengah “pakar” terus berkata:
Dia meninggalkan semua orang tergamam, seolah-olah dia telah menguasai senjata nuklear dalam perdagangan kuantitatif.
Tapi awak nak dia tunjukkan kod tu pada awak?
“Ini… rahsia perdagangan, dan saya tidak boleh mendedahkannya.”
Minta dia jelaskan prinsip tersebut.
“Ini… melibatkan matematik lanjutan, awak takkan faham walaupun saya terangkan kepada awak.”
Hari ini, kita akan meneroka topik yang sering disebut oleh “pakar Zhihu” ini, memperkenalkan aplikasi praktikal transformasi wavelet dalam pasaran kewangan, dan membantu semua orang membangunkan pemahaman yang betul tentang teknologi ini.
Bayangkan anda sedang mendengar lagu, tetapi terdapat bunyi latar belakang dalam rakaman itu:
Rakaman asal = suara manusia + bunyi latar belakang + statik
Transformasi gelombang adalah sepertiPenapis Pintar:
Beralih ke pasaran kewangan:
Harga Asal = Trend Sebenar + Turun Naik Jangka Pendek + Bunyi Rawak
Transformasi gelombang boleh membantu anda:
Intipati transformasi gelombang kecil ialahUraikan isyarat asal menggunakan set “fungsi asas” tertentu (wavelet).。
Bayangkan anda ingin menggambarkan penampilan seseorang:
Dalam harga kewangan:
Siri harga asal = Fungsi asas 1 × Pemberat 1 + Fungsi asas 2 × Pemberat 2 + … + Hingar
Fungsi asas ialah “templat” yang sepadan dengan pekali wavelet.Jenis wavelet yang berbeza (Haar, Daubechies, Mexican Hat, dll.) menggunakan templat yang berbeza, sama seperti menggunakan “pengekstrak ciri” yang berbeza untuk menguraikan harga.
Transformasi gelombang pada asasnya adalah…Bank penapis berbilang skala:
Penapis frekuensi tinggi → Menangkap turun naik pantas (bunyi harian, turun naik tahap tik) Penapis frekuensi pertengahan → Menangkap trend jangka sederhana (jalur antara beberapa jam hingga beberapa hari). Penapis frekuensi rendah → Tangkap trend jangka panjang (trend mingguan dan bulanan).
Mengapa ia dipanggil “gelombang kecil”?
Masalah dengan penggunaan gelombang sinus untuk menganalisis harga kewangan: Gelombang sinus mengandaikan bahawa isyarat berulang secara berkala, tetapi pasaran kewangan tidak! BTC mungkin meningkat 10% hari ini dan jatuh 8% esok, tanpa sebarang kitaran.
Kelebihan wavelet:Analisis penyetempatanIa boleh memberitahu anda “trend harga terutamanya meningkat antara jam 3 petang dan 5 petang pada 20 Disember 2025”, dan bukannya kesimpulan umum seperti “keseluruhan pasaran berubah-ubah”.
Transformasi gelombang ialahBoleh diterbalikkanIni sangat penting!
Harga asal —> Penguraian gelombang —> Komponen trend + Komponen volatiliti + Komponen hingar Komponen trend + komponen turun naik + komponen hingar —> pembinaan semula wavelet —> harga asal
Proses pemfaktoran semulaIa adalah untuk menguraikan pelbagai komponen.Gabungkan kembali secara selektif:
Hanya gunakan komponen trend semasa pembinaan semula
Selepas penguraian, perkara berikut diperolehi
Dalam transaksi sebenar, kita biasanyaBina semula hanya bahagian frekuensi rendah(Trend) Komponen frekuensi tinggi (hingar) dibuang terus. Inilah prinsip “pengurangan hingar” gelombang kecil.
Mari kita langkau formula kamiran yang kompleks dan jelaskannya dalam istilah awam:
Transformasi gelombang = purata berwajaran siri harga menggunakan satu set “pekali gelombang”
Formula asas:
Harga yang meratakan[i] = Σ(harga asal)[i-j] × pekali gelombang kecil[j]) / Σ(pekali gelombang)[j])
Perspektif penapis:
Harga asal ditapis melalui penapis wavelet → komponen frekuensi berbeza “dipilih”.
Kuncinya ialahPemilihan pekali wavelet:
Contohnya:
Dengan mengandaikan anda menggunakan wavelet Daubechies 4, pekalinya ialah[0.483, 0.837, 0.224, -0.129]:
Set pekali ini mentakrifkan penapis:
Transformasi wavelet selesai apabila anda “meluncurkan” penapis ini merentasi keseluruhan siri harga. Setiap slaid melibatkan pengiraan.Purata wajaran harga dalam tempoh semasaPemberatnya ialah pekali wavelet.
Mengapa ia boleh “menguraikan” isyarat?
Kerana ia boleh dibuktikan secara matematik bahawa:Sebarang isyarat boleh diwakili sebagai gabungan linear bagi fungsi asas wavelet.Sama seperti mana-mana warna boleh dicipta dengan mencampurkan tiga warna utama RGB, sebarang siri harga boleh diperoleh dengan menggabungkan fungsi asas wavelet. Jenis wavelet yang berbeza menyediakan “perpustakaan fungsi asas” yang berbeza, sesuai untuk pelbagai jenis analisis isyarat.
Dalam buku teks pemprosesan isyarat, transformasi gelombang biasanya melibatkan…Penguraian berbilang peringkat, pembinaan semula dan penyahbisingan ambangLangkah-langkah:
Aliran kerja analisis wavelet yang lengkap:
TetapiAplikasi praktikal transaksi kewanganDi China, kita tidak memerlukannya menjadi begitu rumit. Kerana:
1. Dagangan hanya memerlukan arah trend; pembinaan semula yang sempurna tidak diperlukan.
Penyelidikan akademik mungkin memerlukan ralat pembinaan semula kurang daripada 0.01%, tetapi dalam perdagangan, ia mencukupi untuk menentukan sama ada harga akan “naik atau turun.” Walaupun pembinaan semula mempunyai ralat 5%, strategi tersebut masih boleh menguntungkan selagi arah trend betul.
2. Keperluan masa nyata memudahkan pengiraan.
Penguraian wavelet yang lengkap memerlukan pengiraan rekursif berbilang lapisan pekali, yang boleh menyebabkan kependaman dalam perdagangan frekuensi tinggi. Sebaliknya, konvolusi langsung boleh diselesaikan dalam milisaat, memenuhi keperluan perdagangan langsung.
3. Ciri-ciri Khas Isyarat Kewangan
Harga kewangan bukanlah isyarat yang stabil dan tidak menunjukkan kitaran yang ketat. Penguraian frekuensi yang kompleks tidak begitu bermakna di sini; pengekstrakan trend mudah adalah lebih praktikal.
Oleh itu, artikel iniMengekstrak intipati transformasi waveletMemberi tumpuan kepada aspek pasaran kewangan yang paling praktikal:
Penyederhanaan Teras 1: Gunakan hanya pekali anggaran (trend frekuensi rendah)
Penguraian wavelet tradisional → pekali penghampiran + pekali perincian (berbilang lapisan) Aplikasi ini: Hanya mengekalkan pekali anggaran → mendapatkan trend terlicin secara langsung.
Penyederhanaan Teras 2: Konvolusi Langsung, tanpa Penyahbisingan Ambang
Penguraian wavelet tradisional → ambang pekali terperinci → pembinaan semula Aplikasi ini: Konvolusi langsung → untuk mendapatkan harga yang terlicin
Penyederhanaan Teras 3: Abaikan Pemprosesan Sempadan
Wavelet tradisional memerlukan pemprosesan seperti pemanjangan simetri dan pemanjangan sempadan isyarat secara berkala. Aplikasi ini hanya tertumpu pada bahagian tengah; ralat sempadan boleh diterima.
Kaedah pelaksanaan: Konvolusi penapis
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 # 归一化
Fungsi ini adalah…Teras penapis wavelet:
stepParameter membolehkan pelicinan berbilang peringkat (Tahap 1/2/3…).Mengapakah penyederhanaan ini munasabah?
Kerana keperluan penting transaksi adalah:Mencari Trend dalam KebisinganPekali penghampiran transformasi gelombang kecil itu sendiri merupakan “penapis laluan rendah” untuk isyarat, memelihara komponen trend frekuensi rendah, yang sememangnya apa yang kita perlukan.
Walaupun analisis wavelet yang lengkap lebih tepat, dalam perdagangan kewangan:
gunaEnjin pengujian semula tempatan bagi platform Pengkuantitian Pencipta (FMZ)Ia sangat mudah untuk mendapatkan data!
'''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()
Tiada penyepaduan API yang kompleks atau pembersihan data diperlukan; data candlestick piawai boleh diperoleh secara langsung. Ini membolehkan kami mengesahkan kesan sebenar tujuh jenis wavelet dengan cepat, daripada terperangkap dalam pemprosesan data.
Dengan membandingkan prestasi tujuh jenis wavelet biasa (Haar, Daubechies 4, Symlet 4, Biorthogonal 3.3, Mexican Hat, Morlet dan Discrete Meyer) pada harga mata wang kripto, demonstrasi visual berikut disediakan:
Tumpuannya bukan pada ketelitian terbitan matematik, tetapi pada perbandingan visual hasil praktikal.Ini membantu pedagang mengembangkan pemahaman intuitif dan memilih jenis wavelet yang sesuai dengan strategi mereka.
Wavelet Haar ialah jenis wavelet yang paling asas, dengan hanya dua pekali:[0.5, 0.5]Pada asasnya, ia adalah purata mudah bagi dua harga bersebelahan.
Kod teras:
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]
Seperti yang anda lihat, harga yang pada asalnya turun naik secara liar (dari 99,000 hingga 102,000) menjadi agak stabil selepas pemprosesan Haar. Ini adalah kesan “denoising” wavelet - melicinkan turun naik jangka pendek yang ganas, membolehkan anda melihat trend harga yang lebih lancar.

Daubechies 4 (db4 untuk pendek kata) ialah salah satu wavelet yang paling biasa digunakan dalam kejuruteraan. Pekalinya ialah:[0.483, 0.837, 0.224, -0.129]Perhatikan bahawa pekali terakhir ialah…nombor negatifItulah yang menjadikannya unik.
Kod teras:
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
Ciri-ciri Utama:Berat candlestick sebelumnya (0.837) adalah lebih besar daripada harga semasa (0.483)! Ini bermakna db4 lebih menekankan “harga yang baru sahaja berlaku”, dan pekali berat negatif akan mempunyai kesan “pengimbangan” pada harga sebelumnya, seterusnya meningkatkan kelancaran.

Symlet 4 ialah versi Daubechies yang dipertingkatkan, bertujuan untuk simetri yang lebih baik. Pekali:[-0.076, -0.030, 0.498, 0.804, 0.298, -0.099, -0.013, 0.032]。
Kod teras:
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都强,但反应速度更慢
Ciri-ciri Utama:Panjang tetingkap 8 candlestick membolehkan “memori” harga yang lebih lama. Pembalikan trend sebenar mungkin tidak dapat dilihat pada lengkungan yang lancar sehingga selepas 8 candlestick berlalu.

Biorthogonal 3.3 (disingkatkan sebagai bior3.3) ialah wavelet simetri sempurna dengan pekali:[-0.066, 0.283, 0.637, 0.283, -0.066]。
Kod teras:
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
Ciri-ciri Utama:Simetri memastikan tiada “herotan fasa” - lengkung yang licin tidak akan beralih ke kiri atau kanan secara tidak dapat dijelaskan.

Pekali Topi Mexico (juga dikenali sebagai wavelet Ricker):[-0.1, 0.0, 0.4, 0.8, 0.4, 0.0, -0.1]Ia berbentuk seperti sombrero Mexico.
Kod teras:
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
Ciri-ciri Utama:Strukturnya yang “besar di tengah, negatif di kedua-dua hujung” menjadikannya sangat baik dalam pengesanan.titik lengkungan- Detik kritikal apabila harga berbalik daripada trend menaik kepada trend menurun (atau sebaliknya). Pekali pemberat negatif “menghukum” harga yang jauh, dengan cepat menangkap perubahan trend.

Wavelet Morlet adalah berdasarkan taburan Gaussian (normal), dengan pekali:[0.0625, 0.25, 0.375, 0.25, 0.0625]。
Kod teras:
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
Ciri-ciri Utama:Gelombang yang paling “lembut”, ia tidak mempunyai pemberat negatif, dan semua harga dimasukkan secara perlahan ke dalam pengiraan. Lengkung yang terhasil sangat lancar, tetapi kosnya adalah tindak balas yang perlahan – perubahan harga secara tiba-tiba mungkin tidak dapat dilihat sehingga beberapa candlestick kemudian.

Wavelet Meyer Diskret ialah wavelet yang paling kompleks, dengan pekali:[-0.015, -0.025, 0.0, 0.28, 0.52, 0.28, 0.0, -0.025, -0.015]。
Kod teras:
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线之前的中期趋势"
Ciri-ciri Utama:Ia mempunyai pekali paling banyak (9), data sejarah terpanjang, dan kesan pelicinan paling kuat. Ia sesuai untuk mengekstrak “trend mingguan”, tetapi terdapat kelewatan yang besar - walaupun harga telah jatuh sebanyak 10%, lengkungnya mungkin masih menunjukkan “terus meningkat”.

Selepas mengkaji tujuh jenis wavelet, anda sepatutnya perasan satu corak:
Lebih banyak pekali = lihat selanjutnya = pelicinan yang lebih kuat = kependaman yang lebih besar
Haar (2 pekali) → Hanya lihat pada 1 bar → Hampir tidak lancar Daubechies 4 (4 keping) → Lihat 3 sebelum → Sedikit licin Topi Mexico (7) → Lihat 6 sebelum → Pelicinan sederhana Diskret Meyer (9) → Sebelum melihat 8 bar → Pelicinan berat
Kesan pemberat negatif adalah untuk meningkatkan kepekaan dan memudahkan pengesanan perubahan.
Haar/Morlet (tiada pemberat negatif) → Lembut dan licin, tidak sensitif Topi Mexico (negatif di kedua-dua hujung) → Sensitif kepada titik infleksi Daubechies 4 (negatif) → Sensitif terhadap perubahan trend
Peranan simetri = tiada herotan = mengekalkan bentuk asal
Asimetri (Daubechies) → Mungkin beralih ke kiri/kanan Simetri (Biortogonal/Meyer) → Mengekalkan kedudukan tengah
Transformasi gelombang boleh digunakan secara rekursif, seperti anak patung bersarang. Aplikasi pertama dipanggil Tahap 1, menggunakannya sekali lagi pada hasil Tahap 1 dipanggil Tahap 2, dan begitulah seterusnya.
Skala masa yang dilihat pada tahap yang berbeza:
Dengan mengandaikan kita menggunakan carta candlestick 1 jam untuk perdagangan BTC:
Tahap 1 → Perhatikan turun naik jangka pendek dalam tempoh 2-4 jam Aras 2 → Perhatikan trend dalam tempoh 4-8 jam Tahap 3 → Perhatikan trend jangka sederhana dalam tempoh 1-2 hari (strategi yang biasa digunakan) Aras 4 → Perhatikan julat harga 2-4 hari Tahap 5 → Perhatikan trend utama sepanjang 4-8 hari
Perbandingan keputusan sebenar:
Harga BTC asal (carta 1 jam):99500, 99800, 99200, 100200, 99800, 100500, 100100, ...
Pemprosesan Tahap 1: 99600, 99650, 99500, 99900, 99950, 100200, 100250, … (Sedikit lebih lancar, tetapi turun naik masih kelihatan)
Pemprosesan Tahap 3: 99620, 99650, 99700, 99800, 99950, 100100, 100200, … (Diratakan, menunjukkan trend jangka sederhana)
Pemprosesan Tahap 5: 99630, 99640, 99660, 99700, 99760, 99840, 99930, … (Sangat lancar, hanya menunjukkan arah umum)

Prinsip pemilihannya mudah: gunakan Tahap yang sepadan berdasarkan tempoh pegangan anda.
Scalping 15 minit → Tahap 1-2
Dagangan intraday → Tahap 2-3
Lakukan ayunan selama beberapa hari → Tahap 3-4
Analisis trend jangka panjang → Tahap 4-5
Aplikasi transformasi wavelet dalam perdagangan adalah sangat langsung: gunakan lengkung harga terlicin yang dijana untuk menentukan arah trend, dan berdagang apabila trend berubah. Secara khususnya, jika harga penutupan terlicin lebih tinggi daripada sebelumnya, ia menunjukkan trend menaik, jadi terus beli; jika harga penutupan terlicin lebih rendah daripada sebelumnya, ia menunjukkan trend menurun, jadi tutup posisi atau terus jual. Logik ini berkesan kerana wavelet telah menapis turun naik rawak jangka pendek, meninggalkan “naik” atau “turun” sebagai kebarangkalian tinggi perubahan trend tulen, bukannya isyarat palsu yang disebabkan oleh hingar.
# 执行小波变换
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 '空仓'},无需操作")

Sudah tentu, dalam praktiknya, ia tidak semudah itu. Anda boleh menggunakan berbilang tahap wavelet secara serentak, seperti Tahap 2 yang menunjukkan trend jangka pendek dan Tahap 4 yang menunjukkan trend jangka panjang. Hanya buka posisi apabila kedua-duanya bergerak dalam arah yang sama, yang mengurangkan isyarat palsu dengan ketara. Anda juga boleh menambah syarat penapisan lain, seperti memerlukan peningkatan volum dagangan, turun naik yang cukup tinggi, atau penembusan harga di atas tahap utama; semuanya ini boleh meningkatkan kadar kemenangan. Untuk pesanan henti rugi, anda boleh menetapkannya secara dinamik menggunakan julat turun naik harga yang diratakan wavelet; contohnya, henti rugi jika harga jatuh di bawah harga yang diratakan tolak 2 kali ganda ATR. Dalam pengurusan posisi, semakin jelas trend (semakin curam cerun harga yang diratakan), semakin berat saiz posisi; jika trend tidak jelas, gunakan posisi yang lebih ringan atau kekal di luar.
Tetapi idea terasnya tetap sama: gunakan wavelet untuk mengubah harga yang bising menjadi trend yang jelas, dan kemudian buat penilaian berdasarkan trend yang jelas tersebut. Ini jauh lebih dipercayai daripada melihat secara langsung kenaikan dan penurunan pada carta candlestick asal, kerana carta candlestick asal mungkin naik 3% hari ini, turun 2% esok, dan naik 4% lusa. Anda tidak dapat membezakan sama ada ia adalah trend atau turun naik. Lengkung yang diproses oleh wavelet akan memberitahu anda “trend keseluruhan dalam tempoh ini adalah menaik, walaupun terdapat turun naik di antara”.
Dari segi kesan pelicinan praktikal, transformasi wavelet sememangnya boleh memainkan peranan dalam pemprosesan data kewangan: ia boleh menapis beberapa hingar jangka pendek dan membantu mengekstrak maklumat trend yang agak jelas. Walau bagaimanapun, teknik ini juga mempunyai batasan yang ketara—Masalah kelewatan tidak dapat dielakkan sepenuhnya.Walau bagaimanapun, ia hanya boleh memproses data sejarah dan tidak dapat meramalkan trend masa hadapan. Tambahan pula, kesan penggunaan transformasi wavelet sahaja agak terhad; ia perlu digabungkan dengan kaedah analisis lain dan langkah kawalan risiko untuk membina sistem perdagangan yang lengkap.
Sebab utama bagi batasan ini terletak pada sifat unik pasaran kewangan. Dalam bidang pemprosesan isyarat tradisional seperti pengecaman pertuturan dan pemprosesan imej, ciri-ciri hingar adalah agak stabil, dan corak isyarat cenderung berulang. Oleh itu, transformasi gelombang kecil boleh memisahkan isyarat daripada hingar dengan berkesan. Walau bagaimanapun, pasaran kewangan adalah sama sekali berbeza: turun naik yang dianggap sebagai “hingar” hari ini mungkin menjadi “isyarat” yang mencerminkan perubahan pasaran esok; model analitikal yang berkesan sekarang mungkin menjadi tidak berkesan pada masa hadapan.Pasaran itu sendiri tidak pegun dan sentiasa berubah secara dinamik.Tiada hukum yang tidak berubah dalam transformasi wavelet, yang menghendaki aplikasi transformasi wavelet dalam bidang kewangan mesti diselaraskan secara fleksibel mengikut persekitaran pasaran tertentu.
Apabila anda melihat seseorang membesar-besarkan kesan sebenar transformasi wavelet dan transformasi Fourier, cuba tanya soalan-soalan ini: Jenis wavelet yang manakah digunakan? Apakah asas untuk memilih jenis ini dan bukannya yang lain? Bagaimanakah tahap pelicinan ditetapkan? Adakah terdapat keputusan ujian balik dan prosedur pemilihan parameter yang sepadan?Mereka yang benar-benar mempunyai pengetahuan profesional akan dapat menerangkan butiran teknikal utama ini dengan jelas.
Berdasarkan pengetahuan kami yang terhad, kami menjalankan penerokaan praktikal ini.Idea terasnya adalah untuk berkongsi konsep aplikasi transformasi wavelet dengan cara yang mudah dan senang difahami.Artikel ini bertujuan untuk membantu pembaca memperoleh pemahaman asas tentang teknologi ini. Kami sangat menghargai penyelidik kuantitatif yang terlibat secara mendalam dalam bidang ini; jika anda pakar dalam bidang ini, anda dialu-alukan untuk menunjukkan sebarang kekurangan dalam artikel ini—seperti asas teori untuk pemilihan parameter wavelet, kaedah pengoptimuman untuk kombinasi berbilang skala dan laluan pelaksanaan untuk pemilihan wavelet adaptif. Kami dengan rendah hati akan menerima cadangan anda dan terus menambah baik kandungannya.
Fungsi pemplotan: Digunakan dalam enjin ujian belakang tempatan pencipta
'''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.")
Fungsi transaksi: Digunakan pada platform Pencipta
'''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)