IT TIP

지원 저항 알고리즘-기술 분석

itqueen 2020. 12. 29. 08:12
반응형

지원 저항 알고리즘-기술 분석


하루 중 차트가 있고 지원 및 저항 수준을 계산하는 방법을 알아 내려고합니다. 누구든지이를 수행하는 알고리즘을 알고 있거나 좋은 시작점을 알고 있습니까?


예, 매우 간단한 알고리즘은 100 개의 막대와 같은 시간대를 선택한 다음 지역 전환점 또는 Maxima 및 Minima를 찾는 것입니다. Maxima와 Minima는 1 차 및 2 차 도함수 (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의 세 전환점보다 덜 중요합니다.

이것에 대한 확장은 추세선을 계산하는 것입니다. 이제 발견 된 전환점 목록과 함께 각 점을 차례로 가져 와서 다른 두 점을 선택하여 직선 방정식을 맞추십시오. 방정식이 특정 오차 범위 내에서 풀 수있는 경우 경 사진 추세선이 있습니다. 그렇지 않다면 버리고 다음 트리플 포인트로 이동하십시오.

추세선을 계산하기 위해 한 번에 세 개가 필요한 이유는 직선 방정식에서 두 점을 사용할 수 있기 때문입니다. 추세선을 계산하는 또 다른 방법은 모든 전환점 쌍의 직선 방정식을 계산 한 다음 세 번째 점 (또는 둘 이상)이 오차 범위 내에서 동일한 직선에 있는지 확인하는 것입니다. 이 선에 하나 이상의 다른 점이 있으면 빙고에서지지 / 저항 추세선을 계산 한 것입니다.

이게 도움이 되길 바란다. 코드 예제는 없습니다. 어떻게 할 수 있는지에 대한 몇 가지 아이디어를 제공합니다. 요약하자면:

시스템에 대한 입력

  • 룩백 기간 L (막대 수)
  • L 바 종가
  • 평활 계수 (종가 평활)
  • 오차 한계 또는 델타 (일치를 구성하기위한 전환점 사이의 최소 거리)

출력

  • 전환점 목록, tPoints [] (x, y)
  • 각각 선 방정식이있는 잠재적 추세선 목록 (y = mx + c)

편집 : 업데이트

저는 최근에 Donchian Channel 이라는 매우 간단한 지표를 배웠습니다. 기본적으로 20 바에서 가장 높은 채널과 가장 낮은 채널을 표시합니다. 대략적인지지 저항 수준을 표시하는 데 사용할 수 있습니다. 하지만 위-전환점이있는 돈 치안 채널이 더 시원 해요 ^ _ ^


알고리즘 거래 시스템에서 훨씬 덜 복잡한 알고리즘을 사용하고 있습니다.

다음 단계는 알고리즘의 한 측면이며 지원 수준을 계산하는 데 사용됩니다. 저항 수준을 계산하는 방법을 이해하려면 알고리즘 아래의 메모를 읽으십시오.

연산

  1. timeseries를 N 크기의 세그먼트로 분할 (Say, N = 5)
  2. 각 세그먼트의 최소값을 식별하면 모든 세그먼트의 최소값 배열이 있습니다 = : arrayOfMin
  3. (: arrayOfMin) = : minValue의 최소값 찾기
  4. 나머지 값이 범위 (X % of : minValue)에 속하는지 확인합니다 (예, X = 1.3 %).
  5. 별도의 배열 만들기 (: supportArr)
    • 범위 내의 값을 추가하고 다음 값을 제거하십시오. : arrayOfMin
    • 또한 3 단계에서 : minValue를 추가합니다.
  6. 지지 (또는 저항) 계산

    • 이 배열의 평균을 취하십시오 = support_level
    • 지원이 여러 번 테스트되면 강력한 것으로 간주됩니다.
    • strength_of_support = supportArr.length
    • level_type (SUPPORT | RESISTANCE) = 이제 현재 가격이 지지선보다 낮 으면 지원이 역할을 변경하고 저항이됩니다.
  7. : arrayOfMin이 비어있을 때까지 3-7 단계를 반복합니다.

  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);
}

메인 계산기 클래스

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

}

나는 당신이 묻는 것과 같은지지와 저항 추세선을 구현하는 패키지를 모았습니다. 다음은 몇 가지 예입니다.

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

산출

이 예제는 조정 된 종가를 가져 오지만, 일중 데이터가 이미로드되어있는 경우 원시 데이터를 numpy 배열로 공급할 수도 있으며 방금 시세 기호를 제공했을 때와 동일한 알고리즘을 해당 데이터에 구현합니다. .

이것이 정확히 당신이 찾고 있던 것인지 확실하지 않지만 이것이 당신이 시작하는 데 도움이되기를 바랍니다. 코드와 추가 설명은 내가 호스팅 한 GitHub 페이지에서 찾을 수 있습니다 : https://github.com/dysonance/Trendy


다음은 support/ resistance레벨 을 찾는 파이썬 함수입니다.

이 함수는 마지막 거래 가격의 배열을 취하고 각각지지 및 저항 수준 목록을 반환합니다. 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


지지 / 저항을 동적으로 계산하는 또 다른 방법을 알아 냈습니다.

단계 :

  1. 중요한 가격 목록 만들기-범위에있는 각 양초의 고가와 저가가 중요합니다. 이 가격 각각은 기본적으로 가능한 SR (Support / Resistance)입니다.

  2. 각 가격에 점수를 부여하십시오.

  3. 점수를 기준으로 가격을 정렬하고 서로 가까운 가격을 제거합니다 (서로 x % 거리).

  4. 상위 N 개 가격을 인쇄하고 최소 Y 점을 기록하십시오. 이것이 지원 저항입니다. 그것은 ~ 300 개의 다른 주식에서 저에게 매우 잘 맞았습니다.

채점 기법

이것에 가까워 지지만 교차 할 수없는 캔들이 많으면 가격이 강력한 SR 역할을합니다. 따라서이 가격에 가까운 각 캔들 (가격에서 y %의 거리 이내)에 대해 점수에 + S1을 더합니다. 이 가격을 인하하는 각 캔들에 대해 점수에 -S2 (음수)를 추가합니다.

이것은 이것에 점수를 할당하는 방법에 대한 매우 기본적인 아이디어를 제공 할 것입니다.

이제 요구 사항에 따라 조정해야합니다. 내가 만든 일부 조정 및 성능을 크게 향상시킨 것은 다음과 같습니다.

  1. 절단 유형에 따라 점수가 다릅니다. 양초의 몸체가 가격을 인하하면 점수 변화는 -S3이지만 양초의 심지가 가격을 인하하면 점수 변화는 -S4입니다. 여기서 Abs (S3)> Abs (S4)는 심지로 자르는 것보다 몸으로 자르는 것이 더 중요하기 때문입니다.

  2. 종가를 마감했지만 교차 할 수없는 양초가 높거나 (양쪽 양초 2 개보다 높음) 낮 으면 (양쪽 양초 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;
    }

일부 도우미 클래스 :

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의 몇 가지 예입니다.

여기에 이미지 설명 입력

여기에 이미지 설명 입력


Jacob의 공헌을 간단히 읽었습니다. 아래 코드에 문제가있을 수 있습니다. # 이제 min if min1-window <0 : min2 = min (x [(min1 + window) :]) else : 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

알고리즘은 주어진 창 밖에서 2 차 최소값을 찾으려고하지만 np.where (x == min2) [0] [0]에 해당하는 위치는 창 내부의 중복 값으로 인해 창 내부에있을 수 있습니다.


다음은 S / R에 대한 PineScript 코드입니다. Andrew 또는 Nilendu 박사가 논의한 모든 논리를 포함하지는 않지만 확실히 좋은 시작입니다.

https://www.tradingview.com/script/UUUyEoU2-SR-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)

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()

참조 URL : https://stackoverflow.com/questions/8587047/support-resistance-algorithm-technical-analysis

반응형