2011-12-21 92 views
33

我有一個日內圖表,我想知道如何計算 支撐和阻力水平,任何人都知道這樣做的算法,或者一個好的起點?支撐阻力算法 - 技術分析

+0

您可能還需要檢查這個問題: http://stackoverflow.com/questions/14861023/resampling-minute-data – ticktock 2015-02-26 14:28:39

回答

44

是的,一個非常簡單的算法是選擇一個時間範圍,比如說100條,然後查找局部轉折點,或者最大值和最小值。最大值和最小值可以通過使用一階和二階導數(dy/dx和d^2y/dx)從平滑的收盤價計算得出。當dy/dx = 0且d^y/dx爲正值時,當dy/dx = 0且d^2y/dx爲負值時,您有最小值,您有最大值。

實際上,這可以通過迭代平滑的收盤價格序列並查看三個相鄰點來計算。如果分數相對較低/較高/較低,那麼你有一個最大值,否則更高/更低/更高你有一個最小值。您可能希望對此檢測方法進行微調以查看更多點(如5,7),並且只在邊緣點距離中心點一定距離時觸發。這與ZigZag指示器使用的算法類似。

一旦你有局部最大值和最小值,然後你想要在Y方向上尋找相互之間的一定距離內的轉折點集羣。這很簡單。獲取N個轉折點的列表並計算它與每個其他發現的轉折點之間的Y距離。如果距離小於一個固定的常數,那麼你已經找到了兩個「接近」的轉折點,表明可能的支撐/阻力。

然後,您可以對您的S/R線進行排序,因此兩個20美元的轉折點比三個轉折點的價值要低20美元。

對此的擴展將是計算趨勢線。現在發現的轉折點列表依次取每個點並選擇其他兩個點,試圖擬合一條直線方程。如果方程可以在一定的誤差範圍內解決,那麼您的趨勢線是傾斜的。如果沒有,放棄並繼續下一個三重點。

你一次需要三個來計算趨勢線的原因是任何兩點都可以用在直線方程中。計算趨勢線的另一種方法是計算所有轉折點對的直線方程,然後查看第三個點(或多於一個)是否位於誤差範圍內的同一條直線上。如果有一個或多個其他點位於此線上,則表示您計算了Support/Resistance趨勢線。

我希望這會有所幫助。沒有代碼示例對不起,我只是給你一些關於如何完成的想法。總結:

到系統的輸入

  • 回溯週期L(的條數)
  • 收盤價對於L條
  • 平滑因子(平滑收盤價)
  • 誤差或Delta(轉折點之間的最小距離構成匹配)

輸出

  • 轉折點的列表,叫他們tPoints [](X,Y)的潛在趨勢線的
  • 列表,每一個與所述線方程(表達式y = mx + c)中

此致

+0

謝謝安德魯·您詳細的答案,我要檢查 – Yaron 2011-12-22 18:30:47

+0

嗨安德魯,我檢查了你的想法,我仍然不知道如何計算最小值和最大值,因爲我沒有公式y(x =時間值,y =價格),我需要它來獲得第一和第二衍生你能解釋一下嗎?非常感謝你。 Yaron – Yaron 2011-12-25 12:01:15

+0

您需要做的是對平滑收盤價進行數值區分以確定dy/dx:en.m.wikipedia.org/wiki/Numerical_differentiation。之後,再次執行分化以發現d^2y/dx。請注意,還有其他更簡單的方法來查找轉折點,請查看鋸齒形指示器:onlinetradingconcepts.com/TechnicalAnalysis/ZigZag.html – 2011-12-25 16:37:32

3

我把一個包裝實現支持和阻力趨勢線,就像你問的一樣。下面是一些例子幾個例子:

import numpy as np 
import pandas.io.data as pd 
from matplotlib.pyplot import * 
gentrends('fb', window = 1.0/3.0) 

Output

這個例子只是拉調整收盤價,但如果你已經裝載在你盤中的數據也可以給它的原始數據作爲numpy的陣列並且它將對該數據執行相同的算法,就像它只是給它提供一個股票代碼。

不知道這是否正是你正在尋找的,但希望這有助於你開始。代碼和一些更多的解釋可以在GitHub頁面上找到,我擁有它:https://github.com/dysonance/Trendy

+0

謝謝!我會試一試 – Yaron 2014-04-14 10:39:48

+0

它只是找到兩個最大和最小的值,並計算從這些點傳遞的線? – nurettin 2014-08-01 18:36:19

+0

對於這個特定的函數,它找到數據的全局最大值和最小值,然後找到您餵食它的窗口週期的第二大最大值和最小值__outside__。所以,如果你給它一個30個週期的窗口,它會發現距離全局最大值/最小值至少30個週期的最大/最小值。它首先向前看,但如果系列中還沒有剩餘30個時段,那麼它會向後看。在這裏我給它提供一個1.0/3.0的窗口,它將其解釋爲數據長度的三分之一。那裏有其他方法,如果你感興趣,可以提供更靈活的方法:) – 2014-08-01 18:56:16

8

我在算法交易系統中使用的算法不太複雜。

以下步驟是算法的一個方面,用於計算支持級別。請閱讀算法下面的註釋,瞭解如何計算阻力水平。

算法

  1. 歇時間序列成大小爲N的分段(說,N = 5)
  2. 確定每個段的最小值,你將有最小值的所有段的數組=: arrayOfMin
  3. 查找最小值(:arrayOfMin)=:minValue
  4. 查看是否有其餘值落在範圍內(X%of:minValue)(說,X = 1。3%)
  5. 使一個單獨的陣列(:supportArr)
    • 範圍內&添加值從刪除這些值:arrayOfMin
    • 還添加:將來自步驟3
  6. 計算支持minValue(最小值)(或電阻)

    • 藉此陣列的平均值= support_level
    • 如果支持多次測試,那麼它被認爲是強大的。
    • strength_of_support = supportArr.length
    • 水平面類型(SUPPORT |電阻)=現在,如果當前價格低於支撐然後支持變化的作用而成爲電阻
  7. 重複步驟3到7,直到:arrayOfMin爲空

  8. 您將擁有所有支持/阻力值與力量。現在平滑這些值,如果任何支持水平太接近,然後消除其中的一個。
  9. 這些支持/阻力計算考慮支持水平搜索。 考慮到電阻值搜索,您需要執行步驟2至9。請參閱註釋和實現。

注:

  • 調整ň& X的值,以獲得更準確的結果。
    • 例如,對於較低揮發性的股票或股票指數使用(N = 10,X = 1.2%)
    • 對於高揮發性股使用(N = 22,X = 1.5%)
  • 對於阻力,過程是完全相反的(使用最大功能代替最小值)
  • 該算法故意保持簡單以避免複雜性,可以改進以提供更好的結果。

這裏是我的實現:

public interface ISupportResistanceCalculator { 

/** 
* Identifies support/resistance levels. 
* 
* @param timeseries 
*   timeseries 
* @param beginIndex 
*   starting point (inclusive) 
* @param endIndex 
*   ending point (exclusive) 
* @param segmentSize 
*   number of elements per internal segment 
* @param rangePct 
*   range % (Example: 1.5%) 
* @return A tuple with the list of support levels and a list of resistance 
*   levels 
*/ 
Tuple<List<Level>, List<Level>> identify(List<Float> timeseries, 
     int beginIndex, int endIndex, int segmentSize, float rangePct); 
} 

主要計算器類

/** 
* 
*/ 
package com.perseus.analysis.calculator.technical.trend; 

import static com.perseus.analysis.constant.LevelType.RESISTANCE; 
import static com.perseus.analysis.constant.LevelType.SUPPORT; 

import java.util.ArrayList; 
import java.util.Collections; 
import java.util.Date; 
import java.util.LinkedList; 
import java.util.List; 
import java.util.Set; 
import java.util.TreeSet; 

import com.google.common.collect.Lists; 
import com.perseus.analysis.calculator.mean.IMeanCalculator; 
import com.perseus.analysis.calculator.timeseries.ITimeSeriesCalculator; 
import com.perseus.analysis.constant.LevelType; 
import com.perseus.analysis.model.Tuple; 
import com.perseus.analysis.model.technical.Level; 
import com.perseus.analysis.model.timeseries.ITimeseries; 
import com.perseus.analysis.util.CollectionUtils; 

/** 
* A support and resistance calculator. 
* 
* @author PRITESH 
* 
*/ 
public class SupportResistanceCalculator implements 
     ISupportResistanceCalculator { 

    static interface LevelHelper { 

     Float aggregate(List<Float> data); 

     LevelType type(float level, float priceAsOfDate, final float rangePct); 

     boolean withinRange(Float node, float rangePct, Float val); 

    } 

    static class Support implements LevelHelper { 

     @Override 
     public Float aggregate(final List<Float> data) { 
      return Collections.min(data); 
     } 

     @Override 
     public LevelType type(final float level, final float priceAsOfDate, 
       final float rangePct) { 
      final float threshold = level * (1 - (rangePct/100)); 
      return (priceAsOfDate < threshold) ? RESISTANCE : SUPPORT; 
     } 

     @Override 
     public boolean withinRange(final Float node, final float rangePct, 
       final Float val) { 
      final float threshold = node * (1 + (rangePct/100f)); 
      if (val < threshold) 
       return true; 
      return false; 
     } 

    } 

    static class Resistance implements LevelHelper { 

     @Override 
     public Float aggregate(final List<Float> data) { 
      return Collections.max(data); 
     } 

     @Override 
     public LevelType type(final float level, final float priceAsOfDate, 
       final float rangePct) { 
      final float threshold = level * (1 + (rangePct/100)); 
      return (priceAsOfDate > threshold) ? SUPPORT : RESISTANCE; 
     } 

     @Override 
     public boolean withinRange(final Float node, final float rangePct, 
       final Float val) { 
      final float threshold = node * (1 - (rangePct/100f)); 
      if (val > threshold) 
       return true; 
      return false; 
     } 

    } 

    private static final int SMOOTHEN_COUNT = 2; 

    private static final LevelHelper SUPPORT_HELPER = new Support(); 

    private static final LevelHelper RESISTANCE_HELPER = new Resistance(); 

    private final ITimeSeriesCalculator tsCalc; 

    private final IMeanCalculator meanCalc; 

    public SupportResistanceCalculator(final ITimeSeriesCalculator tsCalc, 
      final IMeanCalculator meanCalc) { 
     super(); 
     this.tsCalc = tsCalc; 
     this.meanCalc = meanCalc; 
    } 

    @Override 
    public Tuple<List<Level>, List<Level>> identify(
      final List<Float> timeseries, final int beginIndex, 
      final int endIndex, final int segmentSize, final float rangePct) { 

     final List<Float> series = this.seriesToWorkWith(timeseries, 
       beginIndex, endIndex); 
     // Split the timeseries into chunks 
     final List<List<Float>> segments = this.splitList(series, segmentSize); 
     final Float priceAsOfDate = series.get(series.size() - 1); 

     final List<Level> levels = Lists.newArrayList(); 
     this.identifyLevel(levels, segments, rangePct, priceAsOfDate, 
       SUPPORT_HELPER); 

     this.identifyLevel(levels, segments, rangePct, priceAsOfDate, 
       RESISTANCE_HELPER); 

     final List<Level> support = Lists.newArrayList(); 
     final List<Level> resistance = Lists.newArrayList(); 
     this.separateLevels(support, resistance, levels); 

     // Smoothen the levels 
     this.smoothen(support, resistance, rangePct); 

     return new Tuple<>(support, resistance); 
    } 

    private void identifyLevel(final List<Level> levels, 
      final List<List<Float>> segments, final float rangePct, 
      final float priceAsOfDate, final LevelHelper helper) { 

     final List<Float> aggregateVals = Lists.newArrayList(); 

     // Find min/max of each segment 
     for (final List<Float> segment : segments) { 
      aggregateVals.add(helper.aggregate(segment)); 
     } 

     while (!aggregateVals.isEmpty()) { 
      final List<Float> withinRange = new ArrayList<>(); 
      final Set<Integer> withinRangeIdx = new TreeSet<>(); 

      // Support/resistance level node 
      final Float node = helper.aggregate(aggregateVals); 

      // Find elements within range 
      for (int i = 0; i < aggregateVals.size(); ++i) { 
       final Float f = aggregateVals.get(i); 
       if (helper.withinRange(node, rangePct, f)) { 
        withinRangeIdx.add(i); 
        withinRange.add(f); 
       } 
      } 

      // Remove elements within range 
      CollectionUtils.remove(aggregateVals, withinRangeIdx); 

      // Take an average 
      final float level = this.meanCalc.mean(
        withinRange.toArray(new Float[] {}), 0, withinRange.size()); 
      final float strength = withinRange.size(); 

      levels.add(new Level(helper.type(level, priceAsOfDate, rangePct), 
        level, strength)); 

     } 

    } 

    private List<List<Float>> splitList(final List<Float> series, 
      final int segmentSize) { 
     final List<List<Float>> splitList = CollectionUtils 
       .convertToNewLists(CollectionUtils.splitList(series, 
         segmentSize)); 

     if (splitList.size() > 1) { 
      // If last segment it too small 
      final int lastIdx = splitList.size() - 1; 
      final List<Float> last = splitList.get(lastIdx); 
      if (last.size() <= (segmentSize/1.5f)) { 
       // Remove last segment 
       splitList.remove(lastIdx); 
       // Move all elements from removed last segment to new last 
       // segment 
       splitList.get(lastIdx - 1).addAll(last); 
      } 
     } 

     return splitList; 
    } 

    private void separateLevels(final List<Level> support, 
      final List<Level> resistance, final List<Level> levels) { 
     for (final Level level : levels) { 
      if (level.getType() == SUPPORT) { 
       support.add(level); 
      } else { 
       resistance.add(level); 
      } 
     } 
    } 

    private void smoothen(final List<Level> support, 
      final List<Level> resistance, final float rangePct) { 
     for (int i = 0; i < SMOOTHEN_COUNT; ++i) { 
      this.smoothen(support, rangePct); 
      this.smoothen(resistance, rangePct); 
     } 
    } 

    /** 
    * Removes one of the adjacent levels which are close to each other. 
    */ 
    private void smoothen(final List<Level> levels, final float rangePct) { 
     if (levels.size() < 2) 
      return; 

     final List<Integer> removeIdx = Lists.newArrayList(); 
     Collections.sort(levels); 

     for (int i = 0; i < (levels.size() - 1); i++) { 
      final Level currentLevel = levels.get(i); 
      final Level nextLevel = levels.get(i + 1); 
      final Float current = currentLevel.getLevel(); 
      final Float next = nextLevel.getLevel(); 
      final float difference = Math.abs(next - current); 
      final float threshold = (current * rangePct)/100; 

      if (difference < threshold) { 
       final int remove = currentLevel.getStrength() >= nextLevel 
         .getStrength() ? i : i + 1; 
       removeIdx.add(remove); 
       i++; // start with next pair 
      } 
     } 

     CollectionUtils.remove(levels, removeIdx); 
    } 

    private List<Float> seriesToWorkWith(final List<Float> timeseries, 
      final int beginIndex, final int endIndex) { 

     if ((beginIndex == 0) && (endIndex == timeseries.size())) 
      return timeseries; 

     return timeseries.subList(beginIndex, endIndex); 

    } 

} 

這裏有一些支持類:

public enum LevelType { 

    SUPPORT, RESISTANCE 

} 

public class Tuple<A, B> { 

    private final A a; 

    private final B b; 

    public Tuple(final A a, final B b) { 
     super(); 
     this.a = a; 
     this.b = b; 
    } 

    public final A getA() { 
     return this.a; 
    } 

    public final B getB() { 
     return this.b; 
    } 

    @Override 
    public String toString() { 
     return "Tuple [a=" + this.a + ", b=" + this.b + "]"; 
    }; 

} 

public abstract class CollectionUtils { 

/** 
* Removes items from the list based on their indexes. 
* 
* @param list 
*   list 
* @param indexes 
*   indexes this collection must be sorted in ascending order 
*/ 
public static <T> void remove(final List<T> list, 
     final Collection<Integer> indexes) { 
    int i = 0; 
    for (final int idx : indexes) { 
     list.remove(idx - i++); 
    } 
} 

/** 
* Splits the given list in segments of the specified size. 
* 
* @param list 
*   list 
* @param segmentSize 
*   segment size 
* @return segments 
*/ 
public static <T> List<List<T>> splitList(final List<T> list, 
     final int segmentSize) { 
    int from = 0, to = 0; 
    final List<List<T>> result = new ArrayList<>(); 

    while (from < list.size()) { 
     to = from + segmentSize; 
     if (to > list.size()) { 
      to = list.size(); 
     } 
     result.add(list.subList(from, to)); 
     from = to; 
    } 

    return result; 
} 

} 

/** 
* This class represents a support/resistance level. 
* 
* @author PRITESH 
* 
*/ 
public class Level implements Serializable { 

    private static final long serialVersionUID = -7561265699198045328L; 

    private final LevelType type; 

    private final float level, strength; 

    public Level(final LevelType type, final float level) { 
     this(type, level, 0f); 
    } 

    public Level(final LevelType type, final float level, final float strength) { 
     super(); 
     this.type = type; 
     this.level = level; 
     this.strength = strength; 
    } 

    public final LevelType getType() { 
     return this.type; 
    } 

    public final float getLevel() { 
     return this.level; 
    } 

    public final float getStrength() { 
     return this.strength; 
    } 

    @Override 
    public String toString() { 
     return "Level [type=" + this.type + ", level=" + this.level 
       + ", strength=" + this.strength + "]"; 
    } 

} 
+0

它工作得很好嗎? – experquisite 2015-11-11 23:05:36

+1

是的,它確實工作。但它並不完美,一旦你理解了算法,那麼你必須調整它以獲得更多和更準確的結果。它給你這種靈活性。首先嚐試瞭解步驟,然後我會建議使用庫存數據進行嘗試。請檢查答案的「註釋」部分。 – 2015-11-16 07:38:35

1

我簡要閱讀雅各布的貢獻。我認爲它可能與下面的代碼的一些問題: #現在分鐘 如果分1 - 窗口< 0: MIN2 =分鐘(×[(分1 +窗口):]) 其他: MIN2 = MIN(X [ 0:(MIN1 - 窗口)])

# Now find the indices of the secondary extrema 
max2 = np.where(x == max2)[0][0] # find the index of the 2nd max 
min2 = np.where(x == min2)[0][0] # find the index of the 2nd min 

的算法並試圖找到二次最小值外給定的窗口,但隨後對應的位置,以np.where(X == MIN2)[0] [0]可能位於窗口內部,因爲窗口內可能有重複的值。

2

這裏是一個Python函數找到support/resistance水平

這個函數的最後成交價的numpy的陣列分別返回支持和阻力水平的 列表。 n是要掃描條目的編號 。

def supres(ltp, n): 
    """ 
    This function takes a numpy array of last traded price 
    and returns a list of support and resistance levels 
    respectively. n is the number of entries to be scanned. 
    """ 
    from scipy.signal import savgol_filter as smooth 

    # converting n to a nearest even number 
    if n % 2 != 0: 
     n += 1 

    n_ltp = ltp.shape[0] 

    # smoothening the curve 
    ltp_s = smooth(ltp, (n + 1), 3) 

    # taking a simple derivative 
    ltp_d = np.zeros(n_ltp) 
    ltp_d[1:] = np.subtract(ltp_s[1:], ltp_s[:-1]) 

    resistance = [] 
    support = [] 

    for i in xrange(n_ltp - n): 
     arr_sl = ltp_d[i:(i + n)] 
     first = arr_sl[:(n/2)] # first half 
     last = arr_sl[(n/2):] # second half 

     r_1 = np.sum(first > 0) 
     r_2 = np.sum(last < 0) 

     s_1 = np.sum(first < 0) 
     s_2 = np.sum(last > 0) 

     # local maxima detection 
     if (r_1 == (n/2)) and (r_2 == (n/2)): 
      resistance.append(ltp[i + ((n/2) - 1)]) 

     # local minima detection 
     if (s_1 == (n/2)) and (s_2 == (n/2)): 
      support.append(ltp[i + ((n/2) - 1)]) 

    return support, resistance 

SRC

+0

如果你想繪製這些線條怎麼辦?你會如何找到相應的日期? – cJc 2017-10-13 13:20:16

+0

我想你可以嘗試匹配原始數據的支持/阻力價格,這些價格應該包含日期字段。我已經繪製過這個,但我不記得這個項目! – 2017-10-13 15:09:23