algorithm - sucesion - Algoritmo de resistencia de soporte-Análisis técnico
sucesion de fibonacci finanzas (6)
Aquí hay una función de Python para encontrar niveles de support
/ resistance
Esta función toma una matriz numpy del último precio negociado y devuelve una lista de niveles de soporte y resistencia, respectivamente. n es el número de entradas que se analizará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
Tengo un gráfico intradía y estoy tratando de averiguar cómo calcular los niveles de soporte y resistencia, ¿alguien sabe un algoritmo para hacerlo, o un buen punto de partida?
Arreglé un paquete que implementa líneas de tendencia de soporte y resistencia como lo que preguntas. Aquí hay algunos ejemplos de algunos ejemplos:
import numpy as np
import pandas.io.data as pd
from matplotlib.pyplot import *
gentrends(''fb'', window = 1.0/3.0)
Ese ejemplo simplemente saca los precios ajustados, pero si tiene datos intradiarios cargados, también puede alimentarlo con datos sin procesar como una matriz numpy e implementará el mismo algoritmo en esos datos que si solo le diera un símbolo de cotización .
No estoy seguro de si esto es exactamente lo que estaba buscando, pero espero que esto lo ayude a comenzar. El código y alguna explicación más se pueden encontrar en la página de GitHub donde lo tengo alojado: https://github.com/dysonance/Trendy
Estoy usando un algoritmo mucho menos complejo en mi sistema de comercio algorítmico.
Los siguientes pasos son un lado del algoritmo y se utilizan para calcular los niveles de soporte. Por favor, lea las notas debajo del algoritmo para comprender cómo calcular los niveles de resistencia.
Algoritmo
- Divida las series temporales en segmentos de tamaño N (Diga, N = 5)
- Identifique los valores mínimos de cada segmento, tendrá una matriz de valores mínimos de todos los segmentos =: arrayOfMin
- Encuentre un mínimo de (: arrayOfMin) =: minValue
- Vea si alguno de los valores restantes está dentro del rango (X% de: minValue) (Digamos, X = 1.3%)
- Haz una matriz separada (: supportArr)
- agregue valores dentro del rango y elimine estos valores de: arrayOfMin
- también agregue: minValue del paso 3
Cálculo de soporte (o resistencia)
- Tome una media de esta matriz = nivel de soporte
- Si el soporte se prueba muchas veces, entonces se considera fuerte.
- strength_of_support = supportArr.length
- level_type (SUPPORT | RESISTANCE) = Ahora, si el precio actual está por debajo del soporte, entonces el soporte cambia de rol y se convierte en resistencia
Repita los pasos 3 a 7 hasta que: arrayOfMin esté vacío
- Tendrás todos los valores de soporte / resistencia con una fortaleza. Ahora alise estos valores, si los niveles de soporte son demasiado cercanos, elimine uno de ellos.
- Estos soporte / resistencia se calcularon considerando la búsqueda de niveles de soporte. Debe realizar los pasos 2 a 9 teniendo en cuenta la búsqueda de niveles de resistencia. Por favor, vea las notas y la implementación.
Notas:
- Ajuste los valores de N y X para obtener resultados más precisos.
- Ejemplo, para acciones menos volátiles o uso de índices de acciones (N = 10, X = 1.2%)
- Para uso con alto contenido de materias volátiles (N = 22, X = 1.5%)
- Para resistencia, el procedimiento es exactamente opuesto (use función máxima en lugar de mínimo)
- Este algoritmo se mantuvo deliberadamente simple para evitar la complejidad, se puede mejorar para obtener mejores resultados.
Aquí está mi implementación:
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);
}
Clase de calculadora principal
/**
*
*/
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);
}
}
Aquí hay algunas clases de apoyo:
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 + "]";
}
}
He descubierto otra forma de calcular el Soporte / Resistencia de forma dinámica.
Pasos:
Cree una lista de precios importantes: la cantidad máxima y mínima de cada vela en su rango es importante. Cada uno de estos precios es básicamente un SR probable (Soporte / Resistencia).
Dale a cada precio una puntuación.
Ordene los precios por puntaje y elimine los que están cerca uno del otro (a una distancia de x% el uno del otro).
Imprima los mejores precios de N y tenga un puntaje mínimo de Y. Estas son sus Resistencias de Soporte. Me funcionó muy bien en ~ 300 acciones diferentes.
La técnica de puntuación
Un precio actúa como un fuerte SR si hay muchas velas que se acercan a esto pero no pueden cruzar esto. Entonces, por cada vela que esté cerca de este precio (dentro de una distancia de y% del precio), agregaremos + S1 al puntaje. Por cada vela que corte este precio, agregaremos -S2 (negativo) al puntaje.
Esto debería darle una idea muy básica de cómo asignar puntajes a esto.
Ahora debes ajustarlo de acuerdo a tus requerimientos. Algunos ajustes que hice y que mejoraron mucho el rendimiento son los siguientes:
Puntuación diferente para diferentes tipos de corte. Si el cuerpo de una vela corta el precio, entonces el cambio de puntaje es -S3 pero la mecha de una vela corta el precio, el cambio de puntaje es -S4. Aquí Abs (S3)> Abs (S4) porque cortar por el cuerpo es más importante que cortar con mecha.
Si la vela que cierra cerca del precio pero no puede cruzar es alta (más de dos velas en cada lado) o baja (menos de 2 velas en cada lado), entonces agregue una puntuación más alta que otras velas normales cerrándose cerca de esto.
Si la vela que se cierra cerca de esto es alta o baja, y el precio estaba en una tendencia bajista o una tendencia alcista (al menos y% de movimiento), entonces agregue una puntuación más alta a este punto.
Puede eliminar algunos precios de la lista inicial. Considero un precio solo si es el más alto o el más bajo entre las N velas en ambos lados.
Aquí hay un fragmento de mi código.
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;
}
Algunas clases de ayudantes:
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 +
''}'';
}
}
Algunos ejemplos de SR creados por el código.
Leí brevemente la contribución de Jacob. Creo que puede tener algunos problemas con el siguiente código: # Ahora el min si min1 - ventana <0: min2 = min (x [(min1 + ventana):]) else: min2 = min (x [0: (min1 - ventana)])
# 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
el algoritmo intenta encontrar el valor mínimo secundario fuera de la ventana dada, pero entonces la posición correspondiente a np.where (x == min2) [0] [0] puede estar dentro de la ventana debido a valores posiblemente duplicados dentro de la ventana.
Sí, un algoritmo muy simple es elegir un marco de tiempo, digamos 100 barras, luego buscar puntos de inflexión locales, o Máxima y Mínima. Maxima y Minima se pueden calcular a partir de un precio de cierre suavizado utilizando la primera y la segunda derivada (dy / dx y d ^ 2y / dx). Donde dy / dx = cero y d ^ y / dx es positivo, tienes un mínimo, cuando dy / dx = cero y d ^ 2y / dx es negativo, tienes un máximo.
En términos prácticos, esto podría calcularse iterando sobre su serie suavizada de precios de cierre y observando tres puntos adyacentes. Si los puntos son más bajos / más altos / más bajos en términos relativos, entonces tienes un máximo; de lo contrario, más alto / más bajo / más alto tienes un mínimo. Puede ajustar este método de detección para ver más puntos (digamos 5, 7) y solo disparar si los puntos de borde están a un cierto% del punto central. esto es similar al algoritmo que usa el indicador ZigZag.
Una vez que tienes los máximos y mínimos locales, entonces quieres buscar grupos de puntos de inflexión dentro de una cierta distancia el uno del otro en la dirección Y. esto es simple. Tome la lista de N puntos de inflexión y calcule la distancia Y entre ella y cada uno de los otros puntos de inflexión descubiertos. Si la distancia es menor que una constante fija, ha encontrado dos puntos de inflexión "cercanos", que indican un posible soporte / resistencia.
Luego puede clasificar sus líneas de S / R, por lo que dos puntos de inflexión en $ 20 son menos importantes que tres puntos de inflexión en $ 20, por ejemplo.
Una extensión de esto sería calcular líneas de tendencia. Con la lista de puntos de inflexión descubiertos ahora tome cada punto uno por uno y seleccione otros dos puntos, tratando de ajustar una ecuación en línea recta. Si la ecuación se puede resolver dentro de un cierto margen de error, tiene una línea de tendencia inclinada. Si no, descartar y pasar al siguiente triplete de puntos.
La razón por la que necesita tres a la vez para calcular las líneas de tendencia es que se pueden usar dos puntos en la ecuación de línea recta. Otra forma de calcular las líneas de tendencia sería calcular la ecuación de línea recta de todos los pares de puntos de inflexión, luego ver si un tercer punto (o más de uno) se encuentra en la misma línea recta dentro de un margen de error. Si 1 o más puntos más se encuentran en esta línea, el bingo ha calculado una línea de tendencia de Soporte / Resistencia.
Espero que esto ayude. No hay ejemplos de código, lo siento, solo te doy algunas ideas sobre cómo se podría hacer. En resumen:
Entradas al sistema
- Período de retroceso L (número de barras)
- Precios de cierre para barras en L
- Factor de suavizado (para suavizar el precio de cierre)
- Margen de error o Delta (distancia mínima entre puntos de inflexión para constituir una coincidencia)
Salidas
- Lista de puntos de inflexión, llámalos tPoints [] (x, y)
- Lista de líneas de tendencia potenciales, cada una con la ecuación de línea (y = mx + c)
Atentamente,