지원 저항 알고리즘-기술 분석
하루 중 차트가 있고 지원 및 저항 수준을 계산하는 방법을 알아 내려고합니다. 누구든지이를 수행하는 알고리즘을 알고 있거나 좋은 시작점을 알고 있습니까?
예, 매우 간단한 알고리즘은 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 바에서 가장 높은 채널과 가장 낮은 채널을 표시합니다. 대략적인지지 저항 수준을 표시하는 데 사용할 수 있습니다. 하지만 위-전환점이있는 돈 치안 채널이 더 시원 해요 ^ _ ^
알고리즘 거래 시스템에서 훨씬 덜 복잡한 알고리즘을 사용하고 있습니다.
다음 단계는 알고리즘의 한 측면이며 지원 수준을 계산하는 데 사용됩니다. 저항 수준을 계산하는 방법을 이해하려면 알고리즘 아래의 메모를 읽으십시오.
연산
- timeseries를 N 크기의 세그먼트로 분할 (Say, N = 5)
- 각 세그먼트의 최소값을 식별하면 모든 세그먼트의 최소값 배열이 있습니다 = : arrayOfMin
- (: arrayOfMin) = : minValue의 최소값 찾기
- 나머지 값이 범위 (X % of : minValue)에 속하는지 확인합니다 (예, X = 1.3 %).
- 별도의 배열 만들기 (: supportArr)
- 범위 내의 값을 추가하고 다음 값을 제거하십시오. : arrayOfMin
- 또한 3 단계에서 : minValue를 추가합니다.
지지 (또는 저항) 계산
- 이 배열의 평균을 취하십시오 = support_level
- 지원이 여러 번 테스트되면 강력한 것으로 간주됩니다.
- strength_of_support = supportArr.length
- level_type (SUPPORT | RESISTANCE) = 이제 현재 가격이 지지선보다 낮 으면 지원이 역할을 변경하고 저항이됩니다.
: arrayOfMin이 비어있을 때까지 3-7 단계를 반복합니다.
- 당신은 힘을 가진 모든지지 / 저항 값을 갖게 될 것입니다. 이제 이러한 값을 평활화하십시오. 지원 수준이 너무 가깝다면 그중 하나를 제거하십시오.
- 이러한 지원 / 저항은 지원 수준 검색을 고려하여 계산되었습니다. 저항 수준 검색을 고려하여 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
지지 / 저항을 동적으로 계산하는 또 다른 방법을 알아 냈습니다.
단계 :
중요한 가격 목록 만들기-범위에있는 각 양초의 고가와 저가가 중요합니다. 이 가격 각각은 기본적으로 가능한 SR (Support / Resistance)입니다.
각 가격에 점수를 부여하십시오.
점수를 기준으로 가격을 정렬하고 서로 가까운 가격을 제거합니다 (서로 x % 거리).
상위 N 개 가격을 인쇄하고 최소 Y 점을 기록하십시오. 이것이 지원 저항입니다. 그것은 ~ 300 개의 다른 주식에서 저에게 매우 잘 맞았습니다.
채점 기법
이것에 가까워 지지만 교차 할 수없는 캔들이 많으면 가격이 강력한 SR 역할을합니다. 따라서이 가격에 가까운 각 캔들 (가격에서 y %의 거리 이내)에 대해 점수에 + S1을 더합니다. 이 가격을 인하하는 각 캔들에 대해 점수에 -S2 (음수)를 추가합니다.
이것은 이것에 점수를 할당하는 방법에 대한 매우 기본적인 아이디어를 제공 할 것입니다.
이제 요구 사항에 따라 조정해야합니다. 내가 만든 일부 조정 및 성능을 크게 향상시킨 것은 다음과 같습니다.
절단 유형에 따라 점수가 다릅니다. 양초의 몸체가 가격을 인하하면 점수 변화는 -S3이지만 양초의 심지가 가격을 인하하면 점수 변화는 -S4입니다. 여기서 Abs (S3)> Abs (S4)는 심지로 자르는 것보다 몸으로 자르는 것이 더 중요하기 때문입니다.
종가를 마감했지만 교차 할 수없는 양초가 높거나 (양쪽 양초 2 개보다 높음) 낮 으면 (양쪽 양초 2 개 미만)이 근처에서 종가가 다른 양초보다 높은 점수를 추가합니다.
이 근처의 캔들 종가가 높거나 낮고 가격이 하락 추세 또는 상승 추세 (최소 y % 이동)에 있었다면이 지점에 더 높은 점수를 더하세요.
초기 목록에서 일부 가격을 제거 할 수 있습니다. 양측 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
'IT TIP' 카테고리의 다른 글
git이 cygwin에서 파일을 실행 불가능하게 만드는 것을 막는 방법은 무엇입니까? (0) | 2020.12.29 |
---|---|
PHP SoapClient에서 인증서 확인 비활성화 (0) | 2020.12.29 |
Express.js에서 SSL / https를 강제하는 방법 (0) | 2020.12.29 |
이동 : 고유 한 경우 추가 (0) | 2020.12.29 |
xcode 단위 테스트에서 파일로드 (0) | 2020.12.29 |