支持阻力算法 - 技术分析

时间:2011-12-21 08:43:12

标签: algorithm

我有一个日内图表,我正在试图弄清楚如何计算 支持和阻力水平,任何人都知道这样做的算法,或一个良好的起点?

11 个答案:

答案 0 :(得分:71)

是的,一个非常简单的算法是选择一个时间范围,比如100条,然后寻找局部转折点,或者Maxima和Minima。可以通过使用一阶和二阶导数(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美元。

对此的扩展将是计算趋势线。现在发现转折点列表依次取每个点并选择另外两个点,试图拟合直线方程。如果方程在某个误差范围内是可解的,那么您有一个倾斜的趋势线。如果没有,丢弃并转移到下一个三分点。

为什么一次需要三个来计算趋势线的原因是在直线方程中可以使用任意两个点。计算趋势线的另一种方法是计算所有转折点对的直线方程,然后查看第三个点(或多于一个)是否位于误差范围内的同一直线上。如果此线上有1个或多个其他点,宾果你计算了支撑/阻力趋势线。

我希望这会有所帮助。没有代码示例抱歉,我只是给你一些关于如何完成它的想法。总结:

输入系统

  • 回顾期L(条数)
  • 收取L柱的价格
  • 平滑因子(平稳收盘价)
  • 错误保证金或增量(构成匹配的转折点之间的最小距离)

输出

  • 转折点列表,称之为tPoints [](x,y)
  • 潜在趋势线列表,每个趋势线都有线方程(y = mx + c)

致以最诚挚的问候,

答案 1 :(得分:14)

我在算法交易系统中使用的算法要简单得多。

以下步骤是算法的一部分,用于计算支持级别。请阅读算法下面的注释,以了解如何计算阻力水平。

<强>算法

  1. 将时间序列分成大小为N的段(Say,N = 5)
  2. 确定每个细分的最小值,您将拥有所有细分的最小值数组=:arrayOfMin
  3. 找到(:arrayOfMin)=:minValue
  4. 的最小值
  5. 查看是否有任何剩余值落在范围内(X%:minValue)(说,X = 1.3%)
  6. 创建一个单独的数组(:supportArr)
    • 在范围和范围内添加值从以下列表中删除这些值:arrayOfMin
    • 还添加:步骤3中的minValue
  7. 计算支持(或阻力)

    • 取这个数组的平均值= support_level
    • 如果多次测试支持,那么它被认为是强大的。
    • strength_of_support = supportArr.length
    • level_type (支持|抵制)=现在,如果当前价格低于支撑,则支持改变角色并成为阻力
  8. 重复步骤3到7,直到:arrayOfMin为空

  9. 您将拥有所有支持/阻力值和力量。现在平滑这些值,如果任何支持级别太接近,则消除其中一个。
  10. 考虑支持水平搜索,计算这些支撑/阻力。 考虑到阻力水平搜索,您需要执行步骤2到9。请参阅说明和实施。
  11. 备注:

    • 调整N&amp;的值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 + "]";
        }
    
    }
    

答案 2 :(得分:7)

我整理了一个实现支持和阻力趋势线的软件包,就像你要问的那样。以下是一些示例的示例:

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

答案 3 :(得分:5)

这是一个用于查找support / resistance级别

的python函数
  

此函数采用最后交易价格的numpy数组并返回a   支持和阻力位列表。 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

答案 4 :(得分:4)

我已经想出了另一种动态计算支撑/阻力的方法。

<强>步骤:

  1. 创建重要价格列表 - 您所在范围内每支蜡烛的高低都很重要。这些价格中的每一个基本上都是可能的SR(支持/阻力)。

  2. 给每个价格一个分数。

  3. 按分数对价格进行排序,并删除彼此靠近的价格(彼此相距x%)。

  4. 打印前N个价格并且最低得分为Y.这些是您的支持阻力。它在约300种不同的股票中对我有效。

  5. 评分技巧

    如果有很多蜡烛接近这个但不能越过这个价格,那么价格就像一个强大的SR。 因此,对于接近此价格的每个蜡烛(在距离价格y%的距离内),我们将在评分中添加+ S1。 对于每个降低此价格的蜡烛,我们将在分数中添加-S2(负数)。

    这应该为您提供如何为此分配分数的基本概念。

    现在你必须根据你的要求进行调整。 我做了一些调整,并且改进了很多性能如下:

    1. 不同类型的切割得分不同。如果蜡烛的主体削减了价格,则分数变化为-S3,但蜡烛的烛芯会降低价格,分数变化为-S4。这里Abs(S3)&gt; Abs(S4)因为身体切割比用棉芯切割更重要。

    2. 如果关闭价格但不能越过的蜡烛是高(每边高于两支蜡烛)或低(每边低于2支蜡烛),则加上比其他正常更高的分数蜡烛在此附近关闭。

    3. 如果在此附近收盘的蜡烛为高点或低点,价格处于下降趋势或上升趋势(至少y%移动),则在此点加上更高的分数。

    4. 您可以从初始列表中删除一些价格。我只考虑它的两侧N个蜡烛中的最高或最低价格。

    5. 以下是我的代码片段。

          private void findSupportResistance(List<Candle> candles, Long scripId) throws ExecutionException {
              // This is a cron job, so I skip for some time once a SR is found in a stock
              if(processedCandles.getIfPresent(scripId) == null || checkAlways) {
                  //Combining small candles to get larger candles of required timeframe. ( I have 1 minute candles and here creating 1 Hr candles)
                  List<Candle> cumulativeCandles = cumulativeCandleHelper.getCumulativeCandles(candles, CUMULATIVE_CANDLE_SIZE);
                  //Tell whether each point is a high(higher than two candles on each side) or a low(lower than two candles on each side)
                  List<Boolean> highLowValueList = this.highLow.findHighLow(cumulativeCandles);
                  String name = scripIdCache.getScripName(scripId);
                  Set<Double> impPoints = new HashSet<Double>();
                  int pos = 0;
                  for(Candle candle : cumulativeCandles){
                      //A candle is imp only if it is the highest / lowest among #CONSECUTIVE_CANDLE_TO_CHECK_MIN on each side
                      List<Candle> subList = cumulativeCandles.subList(Math.max(0, pos - CONSECUTIVE_CANDLE_TO_CHECK_MIN),
                              Math.min(cumulativeCandles.size(), pos + CONSECUTIVE_CANDLE_TO_CHECK_MIN));
                      if(subList.stream().min(Comparator.comparing(Candle::getLow)).get().getLow().equals(candle.getLow()) ||
                              subList.stream().min(Comparator.comparing(Candle::getHigh)).get().getHigh().equals(candle.getHigh())) {
                          impPoints.add(candle.getHigh());
                          impPoints.add(candle.getLow());
                      }
                      pos++;
                  }
                  Iterator<Double> iterator = impPoints.iterator();
                  List<PointScore> score = new ArrayList<PointScore>();
                  while (iterator.hasNext()){
                      Double currentValue = iterator.next();
                      //Get score of each point
                      score.add(getScore(cumulativeCandles, highLowValueList, currentValue));
                  }
                  score.sort((o1, o2) -> o2.getScore().compareTo(o1.getScore()));
                  List<Double> used = new ArrayList<Double>();
                  int total = 0;
                  Double min = getMin(cumulativeCandles);
                  Double max = getMax(cumulativeCandles);
                  for(PointScore pointScore : score){
                      // Each point should have at least #MIN_SCORE_TO_PRINT point
                      if(pointScore.getScore() < MIN_SCORE_TO_PRINT){
                          break;
                      }
                      //The extremes always come as a Strong SR, so I remove some of them
                      // I also reject a price which is very close the one already used
                      if (!similar(pointScore.getPoint(), used) && !closeFromExtreme(pointScore.getPoint(), min, max)) {
                          logger.info("Strong SR for scrip {} at {} and score {}", name, pointScore.getPoint(), pointScore.getScore());
      //                    logger.info("Events at point are {}", pointScore.getPointEventList());
                          used.add(pointScore.getPoint());
                          total += 1;
                      }
                      if(total >= totalPointsToPrint){
                          break;
                      }
                  }
              }
          }
      
          private boolean closeFromExtreme(Double key, Double min, Double max) {
              return Math.abs(key - min) < (min * DIFF_PERC_FROM_EXTREME / 100.0) || Math.abs(key - max) < (max * DIFF_PERC_FROM_EXTREME / 100);
          }
      
          private Double getMin(List<Candle> cumulativeCandles) {
              return cumulativeCandles.stream()
                      .min(Comparator.comparing(Candle::getLow)).get().getLow();
          }
      
          private Double getMax(List<Candle> cumulativeCandles) {
              return cumulativeCandles.stream()
                      .max(Comparator.comparing(Candle::getLow)).get().getHigh();
          }
      
          private boolean similar(Double key, List<Double> used) {
              for(Double value : used){
                  if(Math.abs(key - value) <= (DIFF_PERC_FOR_INTRASR_DISTANCE * value / 100)){
                      return true;
                  }
              }
              return false;
          }
      
          private PointScore getScore(List<Candle> cumulativeCandles, List<Boolean> highLowValueList, Double price) {
              List<PointEvent> events = new ArrayList<>();
              Double score = 0.0;
              int pos = 0;
              int lastCutPos = -10;
              for(Candle candle : cumulativeCandles){
                  //If the body of the candle cuts through the price, then deduct some score
                  if(cutBody(price, candle) && (pos - lastCutPos > MIN_DIFF_FOR_CONSECUTIVE_CUT)){
                      score += scoreForCutBody;
                      lastCutPos = pos;
                      events.add(new PointEvent(PointEvent.Type.CUT_BODY, candle.getTimestamp(), scoreForCutBody));
                  //If the wick of the candle cuts through the price, then deduct some score
                  } else if(cutWick(price, candle) && (pos - lastCutPos > MIN_DIFF_FOR_CONSECUTIVE_CUT)){
                      score += scoreForCutWick;
                      lastCutPos = pos;
                      events.add(new PointEvent(PointEvent.Type.CUT_WICK, candle.getTimestamp(), scoreForCutWick));
                  //If the if is close the high of some candle and it was in an uptrend, then add some score to this
                  } else if(touchHigh(price, candle) && inUpTrend(cumulativeCandles, price, pos)){
                      Boolean highLowValue = highLowValueList.get(pos);
                      //If it is a high, then add some score S1
                      if(highLowValue != null && highLowValue){
                          score += scoreForTouchHighLow;
                          events.add(new PointEvent(PointEvent.Type.TOUCH_UP_HIGHLOW, candle.getTimestamp(), scoreForTouchHighLow));
                      //Else add S2. S2 > S1
                      } else {
                          score += scoreForTouchNormal;
                          events.add(new PointEvent(PointEvent.Type.TOUCH_UP, candle.getTimestamp(), scoreForTouchNormal));
                      }
                  //If the if is close the low of some candle and it was in an downtrend, then add some score to this
                  } else if(touchLow(price, candle) && inDownTrend(cumulativeCandles, price, pos)){
                      Boolean highLowValue = highLowValueList.get(pos);
                      //If it is a high, then add some score S1
                      if (highLowValue != null && !highLowValue) {
                          score += scoreForTouchHighLow;
                          events.add(new PointEvent(PointEvent.Type.TOUCH_DOWN, candle.getTimestamp(), scoreForTouchHighLow));
                      //Else add S2. S2 > S1
                      } else {
                          score += scoreForTouchNormal;
                          events.add(new PointEvent(PointEvent.Type.TOUCH_DOWN_HIGHLOW, candle.getTimestamp(), scoreForTouchNormal));
                      }
                  }
                  pos += 1;
              }
              return new PointScore(price, score, events);
          }
      
          private boolean inDownTrend(List<Candle> cumulativeCandles, Double price, int startPos) {
              //Either move #MIN_PERC_FOR_TREND in direction of trend, or cut through the price
              for(int pos = startPos; pos >= 0; pos-- ){
                  Candle candle = cumulativeCandles.get(pos);
                  if(candle.getLow() < price){
                      return false;
                  }
                  if(candle.getLow() - price > (price * MIN_PERC_FOR_TREND / 100)){
                      return true;
                  }
              }
              return false;
          }
      
          private boolean inUpTrend(List<Candle> cumulativeCandles, Double price, int startPos) {
              for(int pos = startPos; pos >= 0; pos-- ){
                  Candle candle = cumulativeCandles.get(pos);
                  if(candle.getHigh() > price){
                      return false;
                  }
                  if(price - candle.getLow() > (price * MIN_PERC_FOR_TREND / 100)){
                      return true;
                  }
              }
              return false;
          }
      
          private boolean touchHigh(Double price, Candle candle) {
              Double high = candle.getHigh();
              Double ltp = candle.getLtp();
              return high <= price && Math.abs(high - price) < ltp * DIFF_PERC_FOR_CANDLE_CLOSE / 100;
          }
      
          private boolean touchLow(Double price, Candle candle) {
              Double low = candle.getLow();
              Double ltp = candle.getLtp();
              return low >= price && Math.abs(low - price) < ltp * DIFF_PERC_FOR_CANDLE_CLOSE / 100;
          }
      
          private boolean cutBody(Double point, Candle candle) {
              return Math.max(candle.getOpen(), candle.getClose()) > point && Math.min(candle.getOpen(), candle.getClose()) < point;
          }
      
          private boolean cutWick(Double price, Candle candle) {
              return !cutBody(price, candle) && candle.getHigh() > price && candle.getLow() < price;
          }
      

      一些助手课程:

      public class PointScore {
          Double point;
          Double score;
          List<PointEvent> pointEventList;
      
          public PointScore(Double point, Double score, List<PointEvent> pointEventList) {
              this.point = point;
              this.score = score;
              this.pointEventList = pointEventList;
          }
      }
      
      
      
          public class PointEvent {
          public enum Type{
              CUT_BODY, CUT_WICK, TOUCH_DOWN_HIGHLOW, TOUCH_DOWN, TOUCH_UP_HIGHLOW, TOUCH_UP;
          }
      
          Type type;
          Date timestamp;
          Double scoreChange;
      
          public PointEvent(Type type, Date timestamp, Double scoreChange) {
              this.type = type;
              this.timestamp = timestamp;
              this.scoreChange = scoreChange;
          }
      
          @Override
          public String toString() {
              return "PointEvent{" +
                      "type=" + type +
                      ", timestamp=" + timestamp +
                      ", points=" + scoreChange +
                      '}';
          }
      }
      

      代码创建的SR的一些示例。

      enter image description here

      enter image description here

答案 5 :(得分:1)

我简要介绍了雅各布的贡献。我认为以下代码可能存在一些问题:     #现在分钟     如果min1 - window&lt; 0:         min2 = min(x [(min1 + window):])     其他:         min2 = min(x [0:(min1 - window)])

# 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]的位置可能位于窗口内部,因为内部可能存在重复值。窗口。

答案 6 :(得分:0)

这是S / R的PineScript代码。它不包括安德鲁或尼伦杜博士讨论的所有逻辑,但绝对是一个好的开始:

https://www.tradingview.com/script/UUUyEoU2-S-R-Barry-extended-by-PeterO/

//@version=3
study(title="S/R Barry, extended by PeterO", overlay=true)
FractalLen=input(10)
isFractal(x) => highestbars(x,FractalLen*2+1)==-FractalLen

sF=isFractal(-low), support=low, support:=sF ? low[FractalLen] : support[1]
rF=isFractal(high), resistance=high, resistance:=rF ? high[FractalLen] : resistance[1]
plot(series=support, color=sF?#00000000:blue, offset=-FractalLen)
plot(series=resistance, color=rF?#00000000:red, offset=-FractalLen)

supportprevious=low, supportprevious:=sF ? support[1] : supportprevious[1]
resistanceprevious=low, resistanceprevious:=rF ? resistance[1] : resistanceprevious[1]
plot(series=supportprevious, color=blue, style=circles, offset=-FractalLen)
plot(series=resistanceprevious, color=red, style=circles, offset=-FractalLen)

答案 7 :(得分:0)

我发现获得SR级别的最佳方法是聚类。计算最大值和最小值,然后将这些值展平(如散点图,其中x是最大值和最小值,y始终为1)。然后,您可以使用Sklearn对这些值进行聚类。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.cluster import AgglomerativeClustering

# Calculate VERY simple waves
mx = df.High_15T.rolling( 100 ).max().rename('waves')
mn = df.Low_15T.rolling( 100 ).min().rename('waves')

mx_waves = pd.concat([mx,pd.Series(np.zeros(len(mx))+1)],axis = 1)
mn_waves = pd.concat([mn,pd.Series(np.zeros(len(mn))+-1)],axis = 1)    

mx_waves.drop_duplicates('waves',inplace = True)
mn_waves.drop_duplicates('waves',inplace = True)

W = mx_waves.append(mn_waves).sort_index()
W = W[ W[0] != W[0].shift() ].dropna()

# Find Support/Resistance with clustering

# Create [x,y] array where y is always 1
X = np.concatenate((W.waves.values.reshape(-1,1),
                    (np.zeros(len(W))+1).reshape(-1,1)), axis = 1 )

# Pick n_clusters, I chose the sqrt of the df + 2
n = round(len(W)**(1/2)) + 2
cluster = AgglomerativeClustering(n_clusters=n,
          affinity='euclidean', linkage='ward')
cluster.fit_predict(X)
W['clusters'] = cluster.labels_

# I chose to get the index of the max wave for each cluster
W2 = W.loc[W.groupby('clusters')['waves'].idxmax()]

# Plotit
fig, axis = plt.subplots()
for row in W2.itertuples():

    axis.axhline( y = row.waves, 
            color = 'green', ls = 'dashed' )

axis.plot( W.index.values, W.waves.values )
plt.show()

答案 8 :(得分:0)

对支撑位和阻力位的解释非常主观。很多人以不同的方式来做。 […]当我从图表中评估S&R时,我正在寻找两个主要方面:

  • 反弹-必须与水平线有明显的偏离(反弹),才能确定支撑或阻力的水平。

  • 多次触摸-单次触摸转折点不足以表明已建立支撑或阻力位。应该出现多次触摸到相同的大致水平,以便可以通过这些转折点画一条水平线。

源和python实现在这里: https://www.candlestick.ninja/2019/02/identifying-support-and-resistance-part2.html

答案 9 :(得分:0)

如果您正在寻找水平SR线,我希望了解整个分布。但是我认为,仅取最大的histogram也是一个很好的假设。

# python + pandas

spy["Close"][:60].plot()
hist, border = np.histogram(spy["Close"][:60].values, density=False)
sr = border[np.argmax(hist)]
plt.axhline(y=sr, color='r', linestyle='-')

enter image description here

您可能需要调整bins,最终您想绘制整个bin,而不仅仅是下限。

lower_bound = border[np.argmax(hist)]
upper_bound = border[np.argmax(hist) + 1]

PS的基本“想法”与@Nilendu的解决方案非常相似。

答案 10 :(得分:0)

我不确定这是否真的是“支撑和阻力”检测,但是这又是怎么回事:

function getRanges(_nums=[], _diff=1, percent=true) {
    let nums = [..._nums];
    nums.sort((a,b) => a-b);
    
    const ranges = [];
    for (let i=0; i<nums.length; i+=1) {
        const num = nums[i];
        const diff = percent ? perc(_diff, num) : _diff;
        const range = nums.filter( j => isInRange(j, num-diff, num+diff) );
        if (range.length) {
            ranges.push(range);
            nums = nums.slice(range.length);
            i = -1;
        }
    }
    return ranges;
}

function perc(percent, n) {
    return n * (percent * 0.01);
}
function isInRange(n, min, max) {
    return n >= min && n <= max;
}

因此,假设您有一组close价格:

const nums = [12, 14, 15, 17, 18, 19, 19, 21, 28, 29, 30, 30, 31, 32, 34, 34, 36, 39, 43, 44, 48, 48, 48, 51, 52, 58, 60, 61, 67, 68, 69, 73, 73, 75, 87, 89, 94, 95, 96, 98];

,您想将数字相除一个数量,例如相差5(或5%),那么您将获得如下结果数组:

const ranges = getRanges(nums, 5, false) // ranges of -5  to +5
/* [
    [12, 14, 15, 17]
    [18, 19, 19, 21]
    [28, 29, 30, 30, 31, 32]
    [34, 34, 36, 39]
    [43, 44, 48, 48, 48]
    [51, 52]
    [58, 60, 61]
    [67, 68, 69]
    [73, 73, 75]
    [87, 89]
    [94, 95, 96, 98]
]
*/

// or like
//const ranges = getRanges(nums, 5, true)  // ranges of -5% to +5%

因此范围的长度越长,支撑/阻力区域就越重要。

(再次 :不确定是否可以归类为“支撑和阻力”)