2011-12-21 14 views
33

Tengo un gráfico intradía y estoy tratando de averiguar cómo calcular niveles de soporte y resistencia, ¿alguien sabe un algoritmo para hacerlo, o un buen punto de partida?Algoritmo de resistencia de soporte - Análisis técnico

+0

También es posible que desee comprobar esta pregunta: http://stackoverflow.com/questions/14861023/resampling-minute-data – ticktock

Respuesta

44

Sí, un algoritmo muy simple consiste en elegir un intervalo 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 de precios de cierre suavizados y mirando a 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 tenga máximos y mínimos locales, querrá buscar grupos de puntos de inflexión dentro de una cierta distancia entre sí 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.

Podría 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 las 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 dos puntos se pueden usar 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:

Las entradas al sistema

  • período retroactivo L (número de barras)
  • precios de cierre de bares L
  • factor de alisamiento (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, ellos llamar TPoints [] (x, y)
  • Lista de líneas de tendencia potenciales, cada uno con la ecuación de línea (y = mx + c)

Saludos,

+0

Gracias Andrew para su respuesta detallada, voy a verificar que – Yaron

+0

Hola Andrew, verifiqué tu idea, todavía no puedo descifrar cómo calcular los mínimos y los máximos, porque no tengo la fórmula de y (x = valor del tiempo, y = precio), y lo necesito para obtener 1st y 2nd derivativ es, ¿puedes explicarlo? muchas gracias. Yaron – Yaron

+0

Lo que necesita hacer es realizar una diferenciación numérica de los precios de cierre suavizados para determinar dy/dx: en.m.wikipedia.org/wiki/Ndical_differentiation. Después de eso, realice la diferenciación nuevamente para encontrar d^2y/dx. Tenga en cuenta que hay otras formas más simples de encontrar los puntos de inflexión, consulte el indicador de zigzag: onlinetradingconcepts.com/TechnicalAnalysis/ZigZag.html –

3

Armado un paquete que implementa líneas de tendencia de soporte y resistencia como lo que está preguntando. 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) 

Output

Ese ejemplo simplemente tira de los precios de cierre ajustados, pero si usted tiene los datos intradía ya cargados en la que también se puede alimentar datos en bruto como una matriz numpy e implementará el mismo algoritmo en esa información como lo haría si solo le dieras un símbolo.

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

+0

¡Gracias! Lo probaré – Yaron

+0

¿Simplemente encuentra los dos valores más grandes y más pequeños y calcula las líneas que pasan desde esos puntos? – nurettin

+0

Para esta función específica, encuentra el máximo y el mínimo globales de los datos, y luego encuentra el segundo mayor y mínimo ___ fuera_del período de ventana que usted alimenta. Entonces, si le das una ventana de 30 periodos, encontrará el máximo/mínimo más alto que está por lo menos a 30 periodos del máximo/mínimo global. Espera primero, pero si no quedan 30 períodos en la serie, mirará hacia atrás. Aquí le doy una ventana de 1.0/3.0, que interpreta como un tercio de la longitud de los datos. Existen otros métodos que ofrecen algunos enfoques más flexibles si está interesado :) –

8

Estoy usando un algoritmo mucho menos complejo en mi sistema de comercio algorítmico.

Los siguientes pasos son una parte 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 timeseries

  1. rompen en segmentos de tamaño N (digamos, N = 5)
  2. identificar los valores mínimos de cada segmento, tendrá una matriz de valores mínimos de todos los segmentos =: arrayOfMin
  3. Buscar mínimo de (: arrayOfMin) =: minValue
  4. Ver si alguno de los valores restantes está dentro del rango (X% de: minValue) (Digamos, X = 1.3%)
  5. Hacer una matriz separada (: supportArr)
    • agregar valores dentro del rango & eliminar estos valores a partir de: arrayOfMin
    • también añadir: minValue desde el paso 3
  6. Cálculo de apoyo (o resistencia)

    • Tome una media de esta matriz = support_level
    • Si el soporte se prueba muchas veces, entonces se considera fuerte.
    • strength_of_support = supportArr.length
    • level_type (SOPORTE | RESISTENCIA) = Ahora, si el precio actual está por debajo del soporte papel y luego apoyar los cambios y se convierte en la resistencia
  7. Repita los pasos 3 a 7 hasta : arrayOfMin está vacío

  8. Tendrá 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.
  9. Estos soportes/resistencia se calcularon teniendo en cuenta 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:

  • ajustar los valores de N & X para obtener resultados más precisos.
    • ejemplo, para las acciones menos volátiles o índices de equidad usan (N = 10, X = 1,2%)
    • Para altas acciones volátiles utilizar (N = 22, X = 1,5%)
  • Para la resistencia, el procedimiento es exactamente opuesto (use la función máxima en lugar del mínimo)
  • Este algoritmo se mantuvo deliberadamente simple para evitar la complejidad, se puede mejorar para obtener mejores resultados.

Aquí está mi aplicació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); 
} 

principal clase del calculador

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

    } 

} 

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

} 
+0

¿funciona bien? – experquisite

+1

Sí, funciona con seguridad. Pero no es perfecto, una vez que comprenda el algoritmo, tendrá que modificarlo para obtener resultados cada vez más precisos. Te da esa flexibilidad. Primero intente comprender los pasos, entonces recomendaría probarlo con los datos de stock. Por favor, consulte la sección "Notas" de la respuesta. –

1

leo brevemente la contribución de Jacob.Creo que puede tener algunos problemas con el código de abajo: # Ahora el min si mín1 - ventana < 0: mín2 = min (x [min-1 + ventana():]) otra cosa: mín2 = 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 tratar de encontrar el valor min secundaria ventana exterior dado, 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.

2

Aquí es una función de Python para encontrar support/resistance niveles

Esta función toma una matriz de numpy último precio negociado y devuelve una lista de los niveles de soporte y resistencia respectivamente. n es el número de las entradas que se escanean.

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

+0

¿Qué pasaría si quisiera trazar estas líneas? ¿Cómo encontrarías las fechas correspondientes? – cJc

+0

Supongo que puede intentar hacer coincidir los precios de soporte/resistencia en los datos originales, que deben incluir un campo de fecha. Ya tracé esto antes, ¡pero no recuerdo el proyecto! –

Cuestiones relacionadas