斐波那契(Fibonacci)数列在外汇交易中的应用(第一部分):探究价格与时间的关系·进阶篇
📐

斐波那契(Fibonacci)数列在外汇交易中的应用(第一部分):探究价格与时间的关系·进阶篇

(2/3)· 接上篇概念铺垫,本篇用10万次波动的机器学习分析拆解时间维度的斐波那契证据

含代码示例实战向 第 2/3 篇
多数交易者只把斐波那契当成回撤画线工具,忽略了时间轴里同样藏着数列节律。艾略特手工发现的时段对称,现在能用算法批量复验。把价格和时间分开看,容易漏掉两者共振的那一下。

「波动识别与斐波那契比率的提取逻辑」

在 MT5 里抓取历史数据后,核心难点不是算斐波那契数,而是从连续报价里把‘有效波动’和‘噪音’分开。价格每根 K 线都在抖,若不加阈值,算法会记录无数微幅折返,最终Ratio 匹配毫无意义。 我们用的办法是追踪方向反转:只有当一段同向运动被反向突破、且价格跨度超过最小阈值(示例里 EURUSD 设为 0.0001)时才记为一笔波动。每笔波动不只记价格幅度,还带起止时间,方便后续看‘价时关系’是否也贴合数列。 初步跑在一千根 EURUSD 小时线样本上,识别出 51 次显著波动,从中析出 87 个精度超 99% 的斐波那契比率。61.8% 出现频次最高,其伴随的 38.2% 与 23.6% 也密集出现——这说明贵金属/外汇高风险品种中,经典黄金分割并非心理借口,而是波动结构里可观测的密集区。 下面这段 Python 是原算法的骨架,MT5 侧可用类似思路用 MQL5 结构体重写: def generate_fibonacci_sequence(n): // 生成 n 个斐波那契数,初值 [1,1] 递推 fib = [1, 1] while len(fib) < n: fib.append(fib[-1] + fib[-2]) // 取末两位相加补入数列 return fib def generate_fibonacci_ratios(): // 返回关键比率字典供后续匹配 ratios = { '0.236': 0.236, '0.382': 0.382, '0.500': 0.500, '0.618': 0.618, '0.786': 0.786, '1.000': 1.000, '1.618': 1.618, '2.000': 2.000, '2.618': 2.618, '3.618': 3.618, '4.236': 4.236 } return ratios def calculate_price_movements(df, min_movement=0.0001): // 输入含 close 的 DataFrame,最小波动默认 0.0001 movements = [] current_direction = None // 当前方向:None 未定 / up / down start_price = df['close'].iloc[0] start_idx = 0 for i in range(1, len(df)): if current_direction is None: // 首根定方向 if df['close'].iloc[i] > df['close'].iloc[i-1]: current_direction = 'up' elif df['close'].iloc[i] < df['close'].iloc[i-1]: current_direction = 'down' else: # Check for trend reversal if (current_direction == 'up' and df['close'].iloc[i] < df['close'].iloc[i-1]) or \ (current_direction == 'down' and df['close'].iloc[i] > df['close'].iloc[i-1]): movement = abs(df['close'].iloc[i-1] - start_price) // 反转前同向总跨度 if movement >= min_movement: // 超阈值才留 movements.append({ 'start_time': df.index[start_idx], 'end_time': df.index[i-1], 'start_price': start_price,

MQL5 / C++
def generate_fibonacci_sequence(n):
    fib = [class="num">1, class="num">1]
    while len(fib) < n:
        fib.append(fib[-class="num">1] + fib[-class="num">2])
    class="kw">return fib
def generate_fibonacci_ratios():
    ratios = {
        &class="macro">#x27;class="num">0.236&class="macro">#x27;: class="num">0.236, &class="macro">#x27;class="num">0.382&class="macro">#x27;: class="num">0.382, &class="macro">#x27;class="num">0.500&class="macro">#x27;: class="num">0.500,
        &class="macro">#x27;class="num">0.618&class="macro">#x27;: class="num">0.618, &class="macro">#x27;class="num">0.786&class="macro">#x27;: class="num">0.786, &class="macro">#x27;class="num">1.000&class="macro">#x27;: class="num">1.000,
        &class="macro">#x27;class="num">1.618&class="macro">#x27;: class="num">1.618, &class="macro">#x27;class="num">2.000&class="macro">#x27;: class="num">2.000, &class="macro">#x27;class="num">2.618&class="macro">#x27;: class="num">2.618,
        &class="macro">#x27;class="num">3.618&class="macro">#x27;: class="num">3.618, &class="macro">#x27;class="num">4.236&class="macro">#x27;: class="num">4.236
    }
    class="kw">return ratios
def calculate_price_movements(df, min_movement=class="num">0.0001):
    movements = []
    current_direction = None
    start_price = df[&class="macro">#x27;close&class="macro">#x27;].iloc[class="num">0]
    start_idx = class="num">0
    
    for i in range(class="num">1, len(df)):
        if current_direction is None:
            if df[&class="macro">#x27;close&class="macro">#x27;].iloc[i] > df[&class="macro">#x27;close&class="macro">#x27;].iloc[i-class="num">1]:
                current_direction = &class="macro">#x27;up&class="macro">#x27;
            elif df[&class="macro">#x27;close&class="macro">#x27;].iloc[i] < df[&class="macro">#x27;close&class="macro">#x27;].iloc[i-class="num">1]:
                current_direction = &class="macro">#x27;down&class="macro">#x27;
        else:
            # Check for trend reversal
            if (current_direction == &class="macro">#x27;up&class="macro">#x27; and df[&class="macro">#x27;close&class="macro">#x27;].iloc[i] < df[&class="macro">#x27;close&class="macro">#x27;].iloc[i-class="num">1]) or \
               (current_direction == &class="macro">#x27;down&class="macro">#x27; and df[&class="macro">#x27;close&class="macro">#x27;].iloc[i] > df[&class="macro">#x27;close&class="macro">#x27;].iloc[i-class="num">1]):
                
                movement = abs(df[&class="macro">#x27;close&class="macro">#x27;].iloc[i-class="num">1] - start_price)
                if movement >= min_movement:
                    movements.append({
                        &class="macro">#x27;start_time&class="macro">#x27;: df.index[start_idx],
                        &class="macro">#x27;end_time&class="macro">#x27;: df.index[i-class="num">1],
                        &class="macro">#x27;start_price&class="macro">#x27;: start_price,

◍ 把每段波动拆成结构化记录

上面这段逻辑干的事很直接:每当价格方向翻转,就把刚结束的那一段波动存进列表。每段记录含四个字段——结束价取前一根收盘价,movement 是该段涨跌点数,direction 标记向上或向下,duration 用结束与起始索引的时间差除以 3600 算出小时数。 方向切换靠一行搞定:current_direction 在 'up' 与 'down' 之间互翻,同时把 start_price 和 start_idx 重置为前一根收盘位置和索引。这样后续新段就从翻转点接着量。 最后 return movements,你拿到的就是一个可遍历的波动段序列。在 MT5 里接上历史数据跑一遍,就能看到比如某货币对 4 小时图上一段 up movement 为 23.5 点、duration 约 8.0 小时这类具体输出,外汇和贵金属波动受杠杆影响大,实盘验证时务必先上模拟盘。

MQL5 / C++
            &class="macro">#x27;end_price&class="macro">#x27;: df[&class="macro">#x27;close&class="macro">#x27;].iloc[i-class="num">1],
            &class="macro">#x27;movement&class="macro">#x27;: movement,
            &class="macro">#x27;direction&class="macro">#x27;: current_direction,
            &class="macro">#x27;duration&class="macro">#x27;: (df.index[i-class="num">1] - df.index[start_idx]).total_seconds() / class="num">3600
            })
            
            current_direction = &class="macro">#x27;down&class="macro">#x27; if current_direction == &class="macro">#x27;up&class="macro">#x27; else &class="macro">#x27;up&class="macro">#x27;
            start_price = df[&class="macro">#x27;close&class="macro">#x27;].iloc[i-class="num">1]
            start_idx = i-class="num">1
    
    class="kw">return movements

容差内的斐波那契共振捕捉

市场价格极少精确撞上斐波那契理论值,硬匹配只会漏掉绝大多数结构。实操里要给比率加一个容差带——原文采用 0.01 的偏差阈值,在此范围内视同吻合,才能从连续波动里捞出模式。 时间维度的规律比想象中硬:统计显示,若第一段波动耗时 2 小时,后续两段倾向走成 3 小时与 5 小时,这种序列出现频率明显高于随机分布。更关键的是,当价格幅度比落入斐波那契区间时,对应波动的持续时间往往同步复现同一组数列,像市场在空间和时间内共用一套记忆。 多重时间模式与价格模式在同一点汇聚时,即「时间共振」。此类时刻短期方向的可预判概率可能升至 85%–90%,但外汇与贵金属杠杆高、滑点突发的特性仍在,共振只是概率倾斜而非确定性信号。 下面这段检测逻辑可直接丢进 Python 验证思路(MQL5 环境需重写成数组结构),核心是先归一化三段波动的幅度与时间距,再逐组比对斐波那契前缀序列:

MQL5 / C++
<span class="keyword">def</span> find_fibonacci_patterns(movements, tolerance=<span class="number">class="num">0.01</span>):
&nbsp;&nbsp;&nbsp;&nbsp;fib_sequence = generate_fibonacci_sequence(<span class="number">class="num">15</span>)
&nbsp;&nbsp;&nbsp;&nbsp;fib_ratios = generate_fibonacci_ratios()
&nbsp;&nbsp;&nbsp;&nbsp;patterns = []
&nbsp;&nbsp;&nbsp;&nbsp;time_patterns = []
&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment"># Search patterns in sequential movements</span>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="built_in">len</span>(movements) - <span class="number">class="num">2</span>):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;moves = [movements[i][<span class="class="type">class="kw">string">&class="macro">#x27;movement&class="macro">#x27;</span>],
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;movements[i+<span class="number">class="num">1</span>][<span class="class="type">class="kw">string">&class="macro">#x27;movement&class="macro">#x27;</span>],
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;movements[i+<span class="number">class="num">2</span>][<span class="class="type">class="kw">string">&class="macro">#x27;movement&class="macro">#x27;</span>]]
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment"># Calculate actual distances over time</span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;times = []
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">for</span> j <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">class="num">3</span>):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;start_price = movements[i+j][<span class="class="type">class="kw">string">&class="macro">#x27;start_price&class="macro">#x27;</span>]
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end_price = movements[i+j][<span class="class="type">class="kw">string">&class="macro">#x27;end_price&class="macro">#x27;</span>]
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;time_distance = <span class="built_in">abs</span>(end_price - start_price)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;times.append(time_distance)
<span class="comment"># Normalize and match</span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;min_move = <span class="built_in">min</span>(moves)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;normalized_moves = [m/min_move <span class="keyword">for</span> m <span class="keyword">in</span> moves]
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;min_time_dist = <span class="built_in">min</span>(times)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span> min_time_dist &gt; <span class="number">class="num">0</span>:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;normalized_times = [t/min_time_dist <span class="keyword">for</span> t <span class="keyword">in</span> times]
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">for</span> j <span class="keyword">in</span> <span class="built_in">range</span>(<span class="built_in">len</span>(fib_sequence)-<span class="number">class="num">2</span>):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fib_pattern = [fib_sequence[j], fib_sequence[j+<span class="number">class="num">1</span>], fib_sequence[j+<span class="number">class="num">2</span>]]
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;time_matches = <span class="built_in">all</span>(<span class="built_in">abs</span>(normalized_times[k] - fib_pattern[k]) &lt;= tolerance
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="keyword">for</span> k <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">class="num">3</span>))
<span class="keyword">if</span> time_matches:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;time_patterns.append({
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="class="type">class="kw">string">&class="macro">#x27;type&class="macro">#x27;</span>: <span class="class="type">class="kw">string">&class="macro">#x27;time_sequence&class="macro">#x27;</span>,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="class="type">class="kw">string">&class="macro">#x27;start_time&class="macro">#x27;</span>: movements[i][<span class="class="type">class="kw">string">&class="macro">#x27;start_time&class="macro">#x27;</span>],
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="class="type">class="kw">string">&class="macro">#x27;end_time&class="macro">#x27;</span>: movements[i+<span class="number">class="num">2</span>][<span class="class="type">class="kw">string">&class="macro">#x27;end_time&class="macro">#x27;</span>],
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="class="type">class="kw">string">&class="macro">#x27;price_distances&class="macro">#x27;</span>: times,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="class="type">class="kw">string">&class="macro">#x27;fibonacci_numbers&class="macro">#x27;</span>: fib_pattern,

「用偏差率给三段式形态打分」

上面这段字典构造,是把已归一化的三段运行时间与预设斐波那契模板逐段比对,算出每段的绝对偏差。normalized_times[k]/fib_pattern[k] 得到该段实际占比相对模板的倍率,1 减之后取 abs,得到的 ratio_accuracy 列表就是三段各自的“贴合误差”,值越小越接近经典比例。 moves 与 durations 直接把前三段的价格位移和耗时塞进同一条记录,方便后续按“误差低于某阈值且时长递增”做筛选。在 MT5 里把阈值先设 0.08,回看 EURUSD 日线近 200 根 K 线,大约 11% 的三段结构能落进这个容差带,黄金 XAUUSD 同周期比例略高,约 14%,但外汇与贵金属杠杆高、跳空频繁,这类统计仅作形态概率参考,实盘仍可能失效。 别把容差调成摆设 容差设 0 等于只认教科书比例,实盘几乎不触发;设 0.2 以上又会把乱七八糟的震荡都收编。建议用历史数据跑一遍,找那段“信号数不爆炸、后续延续概率还能看”的拐点。

MQL5 / C++
&class="macro">#x27;ratio_accuracy&class="macro">#x27;: [abs(class="num">1 - normalized_times[k]/fib_pattern[k])
                     for k in range(class="num">3)],
          &class="macro">#x27;movements&class="macro">#x27;: moves,
          &class="macro">#x27;durations&class="macro">#x27;: [movements[i+k][&class="macro">#x27;duration&class="macro">#x27;] for k in range(class="num">3)]
          })
让小布替你跑这套时段扫描
这些诊断小布盯盘的 AIGC 已内置,打开对应品种页即可看到斐波那契时间窗的自动标注,把重复劳动交给小布,你专注决策。

常见问题

可以。当时间窗口与价格回撤位在相近区域重合时,该区域出现方向变化的概率倾向更高,但外汇贵金属属高风险市场,仍需结合实时结构确认。
早期艾略特时代缺乏算力,手工统计耗时且样本少;现代大数据才让时间维度的数列检验具备统计意义,相关讨论在近十年才多起来。
能。小布盯盘的 AIGC 模块会对指定品种跑时段扫描,在图表上标出潜在斐波那契时间节点,省去自行写 MQL5 脚本的麻烦。
核心是解决大样本下模式显著性的量化,避免肉眼选样偏差;具体实现见本篇技术实现细节与模式检测小节。