支持阻力算法 - 技术分析

Yar*_*ron 56 algorithm

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

Dr.*_*ABT 79

是的,一个非常简单的算法是选择一个时间范围,比如说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柱的收盘价
  • 平滑因子(平稳收盘价)
  • 误差保证金或Delta(构成匹配的转折点之间的最小距离)

输出

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

最好的祝福,

  • 是的,它实际上非常简单.请在此处查看此前的答案:http://stackoverflow.com/questions/373186/mathematical-derivation-with-c/373265#comment8512055_373265要区分函数,您可以计算[f(x + h) - f(xh)]/2h(其中h = 1且f(x)是您的输入数组).在实践中,这意味着如果你的数组长度为10(索引0..9),那么你计算diff [8] =(输入[9] - 输入[7])/ 2. (4认同)
  • ...通过计算[f(x-2h) - 8f(x + h)+ 8f(xh) - f(x + 2h)]/12h,可以使用五个点执行更精确的微分.再次对于我们的长度为10的数组,这意味着计算diff [7] =(输入[5] - 8*输入[8] + 8*输入[6] - 输入[9])/ 12.正如您所看到的,使用更多点来计算导数意味着您在计算中引入了更多延迟.我建议尝试两者. (2认同)

Pri*_*tre 15

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

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

算法

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

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

  8. 您将获得具有强度的所有支撑/阻力值.现在平滑这些值,如果任何支持级别太接近,则消除其中一个.
  9. 考虑支持水平搜索,计算这些支撑/阻力.考虑到阻力水平搜索,您需要执行步骤2到9.请参阅说明和实施.

笔记:

  • 调整N和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);
}
Run Code Online (Sandbox Code Playgroud)

主要计算器类

/**
 * 
 */
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);

    }

}
Run Code Online (Sandbox Code Playgroud)

以下是一些支持类:

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 + "]";
    }

}
Run Code Online (Sandbox Code Playgroud)


Jac*_*mos 8

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

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

产量

这个例子只是调整了调整后的收盘价,但是如果你已经加载了日内数据,你也可以将原始数据作为一个numpy数组提供给它,它会对那些数据执行相同的算法,就像你只是给它一个股票代码一样. .

不确定这是否正是您所寻找的,但希望这有助于您入门.代码和一些更多的解释可以在我托管它的GitHub页面上找到:https://github.com/dysonance/Trendy


Ped*_*ito 5

这是一个查找support/ resistance级别的python函数

该函数采用一个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
Run Code Online (Sandbox Code Playgroud)

SRC


Nil*_*ndu 5

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

脚步:

  1. 创建重要价格清单-您范围内每支蜡烛的高低都很重要。每个价格基本上都是一个可能的SR(支撑/阻力)。

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

  3. 按分数对价格进行排序,然后删除彼此接近的价格(彼此之间的距离为x%)。

  4. 打印最高的N个价格,并且最低得分为Y。这是您的支撑阻力。它对我适合大约300种不同的股票。

计分技术

如果有很多蜡烛接近但无法穿越,那么价格就是强SR。因此,对于接近该价格(距离价格y%以内)的每支蜡烛,我们将+ S1添加到得分中。对于每条切入该价格的蜡烛,我们将在得分上加上-S2(负)。

这应该使您对如何分配分数有一个非常基本的想法。

现在,您必须根据需要对其进行调整。我进行了一些调整,这些调整大大改善了性能,如下所示:

  1. 不同类型的切分会有不同的分数。如果蜡烛的主体切割价格,则得分变化为-S3,但是蜡烛的烛芯切割价格,得分变化为-S4。此处Abs(S3)> Abs(S4)是因为按主体切割比用芯吸切割更重要。

  2. 如果收盘价收盘但无法交叉的蜡烛价格高(每侧高于两支蜡烛)或低(每侧低于两支蜡烛),则比在此价格附近收盘的其他普通蜡烛增加得分。

  3. 如果收盘价接近此高点或低点,并且价格处于下降趋势或上升趋势(至少y%的波动),则在此点上增加一个更高的分数。

  4. 您可以从初始列表中删除一些价格。我仅考虑价格在两边N支蜡烛中的最高或最低价格。

这是我的代码片段。

    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;
    }
Run Code Online (Sandbox Code Playgroud)

一些帮助程序类:

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 +
                '}';
    }
}
Run Code Online (Sandbox Code Playgroud)

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

在此处输入图片说明

在此处输入图片说明

  • 你是如何将其绘制在 TradingView 上的?您有等效的 Pine 脚本吗? (2认同)