[TOC]

Bài viết này làMột bài học khoa học phổ biến về biến đổi wavelet cho giao dịch thực tiễn.Đoạn mã này là phiên bản giảng dạy đơn giản hóa (bỏ qua các bước phức tạp như phân tích đa cấp, khử nhiễu ngưỡng và tái tạo biến đổi ngược của sóng wavelet chuẩn), chỉ giữ lại các ý tưởng cốt lõi:Sử dụng hệ số wavelet để thực hiện làm mịn đa thang đo trên giá cả nhằm trích xuất thông tin về xu hướng.Thích hợp cho việc phát triển chiến lược và xác thực nhanh chóng, nhưng không phù hợp cho nghiên cứu học thuật hoặc xuất bản bài báo.
Những ai thường xuyên tìm kiếm các chủ đề tài chính và định lượng trên Zhihu chắc hẳn đã từng thấy tình huống này:
Một số “chuyên gia” cứ liên tục nói rằng:
Anh ta khiến mọi người sững sờ, như thể anh ta đã nắm vững vũ khí hạt nhân của giao dịch định lượng.
Nhưng bạn muốn anh ta cho bạn xem mã nguồn à?
“Đây là bí mật kinh doanh, và tôi không thể tiết lộ.”
Hãy yêu cầu anh ấy giải thích nguyên lý.
“Việc này… liên quan đến toán học cao cấp, bạn sẽ không hiểu được ngay cả khi tôi giải thích.”
Hôm nay, chúng ta sẽ cùng tìm hiểu những chủ đề thường được các “chuyên gia Zhihu” nhắc đến, giới thiệu các ứng dụng thực tiễn của phép biến đổi wavelet trong thị trường tài chính, và giúp mọi người hiểu đúng về công nghệ này.
Hãy tưởng tượng bạn đang nghe một bài hát, nhưng có tiếng ồn nền trong bản ghi âm:
Bản ghi âm gốc = giọng nói người + tiếng ồn nền + nhiễu sóng
Biến đổi wavelet giống như mộtBộ lọc thông minh:
Chuyển sang thị trường tài chính:
Giá gốc = Xu hướng thực + Biến động ngắn hạn + Nhiễu ngẫu nhiên
Phép biến đổi wavelet có thể giúp bạn:
Bản chất của phép biến đổi wavelet làPhân tích tín hiệu gốc bằng cách sử dụng một tập hợp các “hàm cơ sở” (wavelets) cụ thể.。
Hãy tưởng tượng bạn muốn mô tả ngoại hình của một người:
Xét về giá trị tài chính:
Giá gốc của dãy sản phẩm = Hàm cơ sở 1 × Trọng số 1 + Hàm cơ sở 2 × Trọng số 2 + … + Nhiễu
Các hàm cơ sở là “khuôn mẫu” tương ứng với các hệ số wavelet.Các loại wavelet khác nhau (Haar, Daubechies, Mexican Hat, v.v.) sử dụng các mẫu khác nhau, giống như việc sử dụng các “bộ trích xuất đặc trưng” khác nhau để phân tích giá cả.
Biến đổi wavelet về bản chất là…Ngân hàng bộ lọc đa thang:
Bộ lọc tần số cao → Thu nhận các biến động nhanh (nhiễu hàng ngày, biến động ở mức độ tick) Bộ lọc tần số trung gian → Nắm bắt các xu hướng trung hạn (các dải tần từ vài giờ đến vài ngày). Bộ lọc tần số thấp → Nắm bắt các xu hướng dài hạn (xu hướng hàng tuần và hàng tháng).
Tại sao nó được gọi là “sóng con”?
Vấn đề khi sử dụng sóng sin để phân tích giá tài chính là: Sóng sin giả định rằng tín hiệu lặp lại theo chu kỳ, nhưng thị trường tài chính thì không! BTC có thể tăng 10% hôm nay và giảm 8% ngày mai, mà không hề có tính chu kỳ nào cả.
Ưu điểm của wavelet:Phân tích định vịNó có thể cho bạn biết “xu hướng giá chủ yếu tăng trong khoảng thời gian từ 3 giờ chiều đến 5 giờ chiều ngày 20 tháng 12 năm 2025”, thay vì một kết luận chung chung như “thị trường nói chung đang biến động”.
Biến đổi wavelet làCó thể đảo ngượcĐiều này rất quan trọng!
Giá gốc —> Phân tích sóng wavelet —> Thành phần xu hướng + Thành phần biến động + Thành phần nhiễu Thành phần xu hướng + thành phần biến động + thành phần nhiễu —> tái tạo sóng wavelet —> giá gốc
Quy trình tái cấu trúcĐó là quá trình phân tách các thành phần khác nhau.Kết hợp lại một cách có chọn lọc:
Chỉ sử dụng các thành phần xu hướng trong quá trình tái cấu trúc.
Sau quá trình phân hủy, thu được các chất sau:
Trong các giao dịch thực tế, chúng ta thườngChỉ tái tạo phần tần số thấp(Xu hướng) Các thành phần tần số cao (nhiễu) được loại bỏ trực tiếp. Đây là nguyên tắc “giảm nhiễu” của sóng wavelet.
Chúng ta hãy bỏ qua các công thức tích phân phức tạp và giải thích bằng ngôn ngữ dễ hiểu:
Biến đổi wavelet = trung bình có trọng số của chuỗi giá sử dụng một tập hợp các “hệ số wavelet”
Công thức cơ bản:
Làm phẳng giá cả[i] = Σ(giá gốc)[i-j] × hệ số sóng nhỏ[j]) / Σ(hệ số sóng con)[j])
Góc nhìn lọc:
Giá gốc được lọc qua bộ lọc wavelet → các thành phần có tần số khác nhau được “lựa chọn”.
Chìa khóa làLựa chọn các hệ số wavelet:
Ví dụ:
Giả sử bạn sử dụng sóng wavelet Daubechies 4, các hệ số là[0.483, 0.837, 0.224, -0.129]:
Tập hợp các hệ số này định nghĩa một bộ lọc:
Quá trình biến đổi wavelet hoàn tất khi bạn “trượt” bộ lọc này trên toàn bộ chuỗi giá. Mỗi lần trượt đều bao gồm các phép tính.Giá trung bình có trọng số trong khoảng thời gian hiện tạiCác trọng số chính là các hệ số wavelet.
Tại sao nó có thể “phân tách” tín hiệu?
Vì điều đó có thể được chứng minh bằng toán học:Bất kỳ tín hiệu nào cũng có thể được biểu diễn dưới dạng tổ hợp tuyến tính của các hàm cơ sở wavelet.Cũng giống như bất kỳ màu sắc nào cũng có thể được tạo ra bằng cách trộn ba màu cơ bản của RGB, bất kỳ chuỗi giá nào cũng có thể được tạo ra bằng cách kết hợp các hàm cơ sở wavelet. Các loại wavelet khác nhau cung cấp các “thư viện hàm cơ sở” khác nhau, phù hợp với các loại phân tích tín hiệu khác nhau.
Trong các sách giáo khoa về xử lý tín hiệu, phép biến đổi wavelet thường bao gồm các thao tác phức tạp…Phân tích đa cấp, tái tạo và khử nhiễu ngưỡngCác bước:
Quy trình phân tích sóng wavelet hoàn chỉnh:
NhưngỨng dụng thực tiễn của các giao dịch tài chínhỞ Trung Quốc, chúng ta không cần mọi thứ phức tạp đến vậy. Bởi vì:
1. Giao dịch chỉ cần xác định hướng xu hướng; không cần thiết phải tái tạo chính xác hoàn toàn xu hướng.
Nghiên cứu học thuật có thể yêu cầu sai số tái tạo nhỏ hơn 0,01%, nhưng trong giao dịch, sai số đó đủ để xác định giá sẽ tăng hay giảm. Ngay cả khi sai số tái tạo là 5%, chiến lược vẫn có thể sinh lời miễn là hướng xu hướng chính xác.
2. Các yêu cầu theo thời gian thực giúp đơn giản hóa việc tính toán.
Phân tích sóng wavelet hoàn chỉnh đòi hỏi tính toán đệ quy nhiều lớp hệ số, điều này có thể gây ra độ trễ trong giao dịch tần suất cao. Mặt khác, phép tích chập trực tiếp có thể được hoàn thành trong vài mili giây, đáp ứng nhu cầu giao dịch trực tiếp.
3. Những đặc điểm đặc biệt của tín hiệu tài chính
Giá cả tài chính không phải là tín hiệu ổn định và không thể hiện tính chu kỳ nghiêm ngặt. Phân tích tần số phức tạp không mấy ý nghĩa ở đây; việc trích xuất xu hướng đơn giản sẽ thiết thực hơn.
Do đó, bài viết nàyTrích xuất tinh túy của phép biến đổi waveletTập trung vào những khía cạnh thực tiễn nhất của thị trường tài chính:
Nguyên tắc đơn giản hóa cốt lõi 1: Chỉ sử dụng các hệ số xấp xỉ (xu hướng tần số thấp)
Phân tích sóng wavelet truyền thống → hệ số xấp xỉ + hệ số chi tiết (đa lớp) Ứng dụng này: Chỉ giữ lại các hệ số gần đúng → trực tiếp thu được xu hướng đã được làm mịn.
Đơn giản hóa cốt lõi 2: Tích chập trực tiếp, không khử nhiễu bằng ngưỡng
Phân tích sóng wavelet truyền thống → ngưỡng hóa các hệ số chi tiết → tái tạo Ứng dụng này: Phép tích chập trực tiếp → để thu được giá cả được làm mịn
Đơn giản hóa cốt lõi 3: Bỏ qua quá trình xử lý ranh giới
Các wavelet truyền thống yêu cầu xử lý như mở rộng đối xứng và mở rộng tuần hoàn các ranh giới tín hiệu. Ứng dụng này chỉ tập trung vào phần giữa; sai sót ở ranh giới là chấp nhận được.
Phương pháp thực hiện: Tích chập bộ lọc
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 # 归一化
Chức năng này là…Cốt lõi của bộ lọc wavelet:
stepCác tham số cho phép làm mịn đa cấp (Cấp 1/2/3…).Tại sao sự đơn giản hóa này lại hợp lý?
Vì yêu cầu thiết yếu của các giao dịch là:Tìm kiếm xu hướng trong tiếng ồnCác hệ số xấp xỉ của phép biến đổi wavelet bản thân chúng là một “bộ lọc thông thấp” cho tín hiệu, bảo toàn các thành phần xu hướng tần số thấp, chính xác là những gì chúng ta cần.
Mặc dù phân tích sóng wavelet đầy đủ chính xác hơn, nhưng trong giao dịch tài chính:
sử dụngCông cụ kiểm thử ngược cục bộ của nền tảng Inventor Quantization (FMZ).Việc lấy dữ liệu rất tiện lợi!
'''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()
Không cần tích hợp API phức tạp hay làm sạch dữ liệu; dữ liệu biểu đồ nến tiêu chuẩn có thể được lấy trực tiếp. Điều này cho phép chúng tôi nhanh chóng xác minh tác động thực tế của bảy loại sóng wavelet, thay vì bị sa lầy vào quá trình xử lý dữ liệu.
Bằng cách so sánh hiệu suất của bảy loại wavelet phổ biến (Haar, Daubechies 4, Symlet 4, Biorthogonal 3.3, Mexican Hat, Morlet và Discrete Meyer) trên giá tiền điện tử, hình ảnh minh họa sau đây được cung cấp:
Trọng tâm không phải là tính chặt chẽ của phép chứng minh toán học, mà là sự so sánh trực quan các kết quả thực tiễn.Điều này giúp các nhà giao dịch phát triển sự hiểu biết trực quan và lựa chọn loại sóng con phù hợp với chiến lược của họ.
Sóng Haar là loại sóng cơ bản nhất, chỉ có hai hệ số:[0.5, 0.5]Về cơ bản, đó chỉ đơn giản là trung bình cộng của hai mức giá liền kề.
Mã nguồn chính:
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]
Như bạn thấy, giá ban đầu biến động mạnh (từ 99.000 đến 102.000) trở nên tương đối ổn định sau khi xử lý bằng sóng Haar. Đây là hiệu ứng “khử nhiễu” của sóng wavelet - làm mượt các biến động mạnh trong ngắn hạn, cho phép bạn thấy được xu hướng giá mượt mà hơn.

Daubechies 4 (viết tắt là db4) là một trong những wavelet được sử dụng phổ biến nhất trong kỹ thuật. Các hệ số của nó là:[0.483, 0.837, 0.224, -0.129]Lưu ý rằng hệ số cuối cùng là…số âmĐó là điều làm nên sự độc đáo của nó.
Mã nguồn chính:
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
Các tính năng chính:Trọng lượng của nến trước đó (0,837) lớn hơn trọng lượng của giá hiện tại (0,483)! Điều này có nghĩa là db4 đặt trọng tâm nhiều hơn vào “giá vừa xảy ra”, và hệ số trọng lượng âm sẽ có tác dụng “bù trừ” cho giá trước đó, giúp tăng cường độ mượt mà hơn nữa.

Symlet 4 là phiên bản cải tiến của Daubechies, hướng đến sự đối xứng tốt hơn. Hệ số:[-0.076, -0.030, 0.498, 0.804, 0.298, -0.099, -0.013, 0.032]。
Mã nguồn chính:
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都强,但反应速度更慢
Các tính năng chính:Khoảng thời gian 8 nến cho phép “ghi nhớ” giá lâu hơn. Một sự đảo chiều xu hướng thực sự có thể không hiển thị rõ trên đường cong mượt mà cho đến khi 8 nến đã trôi qua.

Biorthogonal 3.3 (viết tắt là bior3.3) là một wavelet đối xứng hoàn hảo với các hệ số:[-0.066, 0.283, 0.637, 0.283, -0.066]。
Mã nguồn chính:
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
Các tính năng chính:Tính đối xứng đảm bảo không có “biến dạng pha” - đường cong được làm mịn sẽ không bị dịch chuyển sang trái hoặc phải một cách khó hiểu.

Hệ số sóng nhỏ kiểu Mexico (còn gọi là sóng nhỏ Ricker):[-0.1, 0.0, 0.4, 0.8, 0.4, 0.0, -0.1]Nó có hình dạng giống như một chiếc mũ sombrero của Mexico.
Mã nguồn chính:
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
Các tính năng chính:Cấu trúc “lớn ở giữa, nhỏ ở cả hai đầu” của nó khiến nó đặc biệt hiệu quả trong việc phát hiện.điểm uốn- Thời điểm quan trọng khi giá cả đảo chiều từ xu hướng tăng sang xu hướng giảm (hoặc ngược lại). Hệ số trọng số âm “trừng phạt” các mức giá xa, nhanh chóng nắm bắt sự thay đổi xu hướng.

Sóng Morlet dựa trên phân phối Gaussian (chuẩn), với các hệ số:[0.0625, 0.25, 0.375, 0.25, 0.0625]。
Mã nguồn chính:
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
Các tính năng chính:Là loại wavelet “nhẹ nhàng” nhất, nó không có trọng số âm và tất cả các mức giá đều được kết hợp một cách nhẹ nhàng vào phép tính. Đường cong thu được cực kỳ mượt mà, nhưng nhược điểm là phản hồi chậm – những thay đổi giá đột ngột có thể không được phản ánh cho đến vài nến sau đó.

Sóng wavelet Meyer rời rạc là sóng wavelet phức tạp nhất, với các hệ số:[-0.015, -0.025, 0.0, 0.28, 0.52, 0.28, 0.0, -0.025, -0.015]。
Mã nguồn chính:
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线之前的中期趋势"
Các tính năng chính:Nó có nhiều hệ số nhất (9), dữ liệu lịch sử dài nhất và hiệu ứng làm mịn mạnh nhất. Nó phù hợp để trích xuất “xu hướng hàng tuần”, nhưng có độ trễ rất lớn - ngay cả khi giá đã giảm 10%, đường cong của nó vẫn có thể cho thấy “tiếp tục tăng”.

Sau khi xem xét bảy loại sóng con, bạn hẳn đã nhận thấy một quy luật:
Càng nhiều hệ số = càng nhìn rõ hơn = làm mịn càng mạnh = độ trễ càng lớn
Haar (2 hệ số) → Chỉ xem xét 1 thanh → Hầu như không mượt mà Daubechies 4 (4 miếng) → Xem mục 3 trước → Hơi mịn Mũ Mexico (7) → Xem mục 6 trước đó → Làm mịn vừa phải Meyer rời rạc (9) → Trước khi xem 8 thanh → Làm mịn mạnh
Tác dụng của trọng số âm là tăng cường độ nhạy và giúp dễ dàng phát hiện các thay đổi hơn.
Haar/Morlet (không có trọng số âm) → Nhẹ nhàng và mượt mà, không nhạy cảm Mũ Mexico (phủ định ở cả hai đầu) → Nhạy cảm với các điểm uốn Daubechies 4 (âm) → Nhạy cảm với sự thay đổi xu hướng
Vai trò của tính đối xứng = không bị biến dạng = duy trì hình dạng ban đầu
Tính bất đối xứng (Daubechies) → Có thể dịch chuyển sang trái/phải Đối xứng (Sinh học vuông góc/Meyer) → Duy trì vị trí trung tâm
Phép biến đổi wavelet có thể được áp dụng đệ quy, giống như những con búp bê lồng nhau. Lần áp dụng đầu tiên được gọi là Cấp độ 1, áp dụng lại lên kết quả của Cấp độ 1 được gọi là Cấp độ 2, và cứ thế tiếp tục.
Các thang thời gian được quan sát ở các cấp độ khác nhau:
Giả sử chúng ta sử dụng biểu đồ nến 1 giờ để giao dịch BTC:
Cấp độ 1 → Quan sát các biến động ngắn hạn trong vòng 2-4 giờ Cấp độ 2 → Quan sát xu hướng trong vòng 4-8 giờ Cấp độ 3 → Quan sát xu hướng trung hạn trong 1-2 ngày (chiến lược thường dùng) Cấp độ 4 → Quan sát phạm vi giá 2-4 ngày Cấp độ 5 → Quan sát các xu hướng chính trong vòng 4-8 ngày
So sánh kết quả thực tế:
Giá BTC gốc (biểu đồ 1 giờ):99500, 99800, 99200, 100200, 99800, 100500, 100100, ...
Xử lý cấp 1: 99600, 99650, 99500, 99900, 99950, 100200, 100250, … (Đã được làm mịn đôi chút, nhưng vẫn còn thấy rõ sự dao động)
Xử lý cấp 3: 99620, 99650, 99700, 99800, 99950, 100100, 100200, … (Đã được làm mịn, thể hiện xu hướng trung hạn)
Xử lý cấp độ 5: 99630, 99640, 99660, 99700, 99760, 99840, 99930, … (Rất mượt mà, chỉ thể hiện hướng tổng quát)

Nguyên tắc lựa chọn rất đơn giản: sử dụng Mức độ tương ứng dựa trên thời gian nắm giữ của bạn.
Giao dịch lướt sóng 15 phút → Cấp độ 1-2
Giao dịch trong ngày → Cấp độ 2-3
Tập swing vài ngày → Cấp độ 3-4
Phân tích xu hướng dài hạn → Cấp độ 4-5
Ứng dụng của phép biến đổi wavelet trong giao dịch rất trực quan: sử dụng đường cong giá được làm mịn mà nó tạo ra để xác định hướng xu hướng và giao dịch khi xu hướng thay đổi. Cụ thể, nếu giá đóng cửa được làm mịn cao hơn giá trước đó, điều đó cho thấy xu hướng tăng, vì vậy hãy mua vào; nếu giá đóng cửa được làm mịn thấp hơn giá trước đó, điều đó cho thấy xu hướng giảm, vì vậy hãy đóng vị thế hoặc bán ra. Logic này hiệu quả vì wavelet đã lọc bỏ các biến động ngẫu nhiên ngắn hạn, chỉ giữ lại tín hiệu “tăng” hoặc “giảm” với xác suất cao là sự thay đổi xu hướng thực sự, chứ không phải là tín hiệu sai do nhiễu gây ra.
# 执行小波变换
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 '空仓'},无需操作")

Tất nhiên, trên thực tế, mọi chuyện không đơn giản như vậy. Bạn có thể sử dụng nhiều cấp độ wavelet cùng lúc, chẳng hạn như Cấp độ 2 thể hiện xu hướng ngắn hạn và Cấp độ 4 thể hiện xu hướng dài hạn. Chỉ mở vị thế khi cả hai đều di chuyển cùng hướng, điều này giúp giảm đáng kể các tín hiệu sai. Bạn cũng có thể thêm các điều kiện lọc khác, chẳng hạn như yêu cầu khối lượng giao dịch tăng, độ biến động đủ cao hoặc giá phá vỡ mức kháng cự quan trọng; tất cả những điều này đều có thể cải thiện tỷ lệ thắng. Đối với lệnh cắt lỗ, bạn có thể thiết lập động bằng cách sử dụng phạm vi biến động giá được làm mịn bằng wavelet; ví dụ, cắt lỗ nếu giá giảm xuống dưới giá được làm mịn trừ đi 2 lần ATR. Trong quản lý vị thế, xu hướng càng rõ ràng (độ dốc của giá được làm mịn càng lớn), quy mô vị thế càng lớn; nếu xu hướng không rõ ràng, hãy sử dụng vị thế nhỏ hơn hoặc đứng ngoài cuộc.
Nhưng ý tưởng cốt lõi vẫn giữ nguyên: sử dụng sóng wavelet để chuyển đổi giá cả nhiễu thành các xu hướng rõ ràng, và sau đó đưa ra phán đoán dựa trên các xu hướng rõ ràng đó. Điều này đáng tin cậy hơn nhiều so với việc trực tiếp nhìn vào sự tăng giảm trên biểu đồ nến ban đầu, bởi vì biểu đồ nến ban đầu có thể tăng 3% hôm nay, giảm 2% ngày mai và tăng 4% ngày kia. Bạn đơn giản là không thể phân biệt được đó là xu hướng hay chỉ là biến động. Đường cong được xử lý bằng sóng wavelet sẽ cho bạn biết “xu hướng tổng thể trong giai đoạn này là tăng, mặc dù có những biến động xen kẽ”.
Về mặt hiệu quả làm mịn thực tế, biến đổi wavelet thực sự có thể đóng vai trò trong xử lý dữ liệu tài chính: nó có thể lọc bỏ một số nhiễu ngắn hạn và giúp trích xuất thông tin xu hướng tương đối rõ ràng. Tuy nhiên, kỹ thuật này cũng có những hạn chế đáng kể—Vấn đề độ trễ không thể hoàn toàn tránh khỏi.Tuy nhiên, nó chỉ có thể xử lý dữ liệu lịch sử và không thể dự đoán xu hướng tương lai. Hơn nữa, hiệu quả của việc chỉ sử dụng biến đổi wavelet là tương đối hạn chế; nó cần được kết hợp với các phương pháp phân tích khác và các biện pháp kiểm soát rủi ro để xây dựng một hệ thống giao dịch hoàn chỉnh.
Lý do cốt lõi của hạn chế này nằm ở bản chất độc đáo của thị trường tài chính. Trong các lĩnh vực xử lý tín hiệu truyền thống như nhận dạng giọng nói và xử lý ảnh, đặc điểm của nhiễu tương đối ổn định, và các mẫu tín hiệu có xu hướng lặp lại. Do đó, phép biến đổi wavelet có thể tách tín hiệu khỏi nhiễu một cách hiệu quả. Tuy nhiên, thị trường tài chính hoàn toàn khác: những biến động được coi là “nhiễu” ngày hôm nay có thể trở thành “tín hiệu” phản ánh sự thay đổi của thị trường vào ngày mai; các mô hình phân tích hiệu quả hiện nay có thể trở nên không hiệu quả trong tương lai.Thị trường vốn dĩ không ổn định và luôn biến động.Không có quy luật bất biến nào trong phép biến đổi wavelet, điều này đòi hỏi việc ứng dụng phép biến đổi wavelet trong lĩnh vực tài chính phải được điều chỉnh linh hoạt theo môi trường thị trường cụ thể.
Khi bạn thấy ai đó phóng đại tác động thực tế của phép biến đổi wavelet và phép biến đổi Fourier, hãy thử đặt những câu hỏi sau: Loại wavelet nào đã được sử dụng? Cơ sở nào để chọn loại này thay vì các loại khác? Mức độ làm mịn được thiết lập như thế nào? Có kết quả kiểm thử ngược và quy trình lựa chọn tham số tương ứng không?Những người thực sự có kiến thức chuyên môn sẽ có thể giải thích rõ ràng những chi tiết kỹ thuật quan trọng này.
Dựa trên kiến thức hạn chế của mình, chúng tôi đã tiến hành cuộc khảo sát thực tiễn này.Ý tưởng cốt lõi là chia sẻ các khái niệm ứng dụng của phép biến đổi wavelet một cách đơn giản và dễ hiểu.Bài viết này nhằm mục đích giúp người đọc có được hiểu biết cơ bản về công nghệ này. Chúng tôi đánh giá cao các nhà nghiên cứu định lượng đang chuyên sâu trong lĩnh vực này; nếu bạn là chuyên gia trong lĩnh vực này, vui lòng chỉ ra bất kỳ thiếu sót nào trong bài viết — chẳng hạn như cơ sở lý thuyết cho việc lựa chọn tham số wavelet, phương pháp tối ưu hóa cho các tổ hợp đa thang đo và các lộ trình triển khai cho việc lựa chọn wavelet thích ứng. Chúng tôi sẽ trân trọng tiếp nhận những góp ý của bạn và liên tục cải thiện nội dung.
Chức năng vẽ đồ thị: Được áp dụng trong công cụ kiểm thử ngược cục bộ của nhà phát minh.
'''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.")
Chức năng giao dịch: Được áp dụng trên nền tảng Nhà phát minh.
”`python “‘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 # 平滑阶数