2011-12-21 18 views
33

Ho un grafico intra-day e sto cercando di capire come calcolare i livelli di supporto e resistenza , qualcuno conosce un algoritmo per farlo o un buon punto di partenza?Support Resistance Algorithm - Analisi tecnica

+0

Si consiglia inoltre di controllare questa domanda: http://stackoverflow.com/questions/14861023/resampling-minute-data – ticktock

risposta

44

Sì, un algoritmo molto semplice è quello di scegliere un intervallo di tempo, ad esempio 100 bar, quindi cercare punti di svolta locali o Maxima e Minima. I massimi e i minimi possono essere calcolati da un prezzo di chiusura arrotondato utilizzando la derivata 1a e 2a (dy/dx e d^2y/dx). Dove dy/dx = zero e d^y/dx è positivo, hai un minimo, quando dy/dx = zero e d^2y/dx è negativo, hai un massimo.

In termini pratici, questo potrebbe essere calcolato iterando sulle serie di prezzi di chiusura uniformi e osservando tre punti adiacenti. Se i punti sono inferiori/superiori/inferiori in termini relativi, allora hai un massimo, altrimenti più alto/basso/più alto hai un minimo. Potresti voler mettere a punto questo metodo di rilevamento per guardare più punti (ad esempio 5, 7) e attivare solo se i punti di bordo sono a una certa percentuale di distanza dal punto centrale. questo è simile all'algoritmo usato dall'indicatore ZigZag.

Una volta raggiunti i massimi e i minimi locali, è necessario cercare gruppi di punti di svolta a una certa distanza l'uno dall'altro nella direzione Y. questo è semplice Prendi la lista dei N punti di svolta e calcola la distanza Y tra essa e ciascuno degli altri punti di svolta scoperti. Se la distanza è inferiore a una costante fissa, hai trovato due punti di svolta "vicini", indicando un possibile supporto/resistenza.

Puoi quindi classificare le tue linee S/R, quindi due punti di svolta a $ 20 sono meno importanti di tre punti di svolta a $ 20 per esempio.

Un'estensione a questo sarebbe il calcolo delle linee di tendenza. Con l'elenco dei punti di svolta scoperti ora prendi ogni punto a turno e seleziona altri due punti, cercando di adattare un'equazione a linea retta. Se l'equazione è risolvibile entro un certo margine di errore, si ha una linea di tendenza in pendenza. In caso contrario, scartare e passare alla successiva tripletta di punti.

Il motivo per cui è necessario tre alla volta per calcolare le linee di tendenza è che è possibile utilizzare due punti nell'equazione della linea retta. Un altro modo per calcolare le linee di tendenza sarebbe calcolare l'equazione in linea retta di tutte le coppie di punti di svolta, quindi vedere se un terzo punto (o più di uno) si trova sulla stessa linea retta all'interno di un margine di errore. Se 1 o più punti si trovano su questa linea, bingo hai calcolato una linea di tendenza di supporto/resistenza.

Spero che questo aiuti. Nessun esempio di codice mi dispiace, ti sto solo dando alcune idee su come potrebbe essere fatto.In sintesi:

ingressi al sistema

  • periodo Lookback L (numero di barre)
  • prezzi di chiusura di L bar
  • Smoothing fattore (per lisciare prezzo di chiusura)
  • margine di errore o Delta (distanza minima tra i punti di svolta per costituire una corrispondenza)

Uscite

  • Elenco dei punti di svolta, chiamarli TPoints [] (x, y)
  • Elenco di potenziali linee di tendenza, ciascuno con l'equazione linea (y = mx + c)

saluti,

+0

Grazie Andrea per la vostra risposta dettagliata, vado a verificare che – Yaron

+0

Ciao Andrew, ho verificato la tua idea, non riesco ancora a capire come calcolare i minimi e i massimi, perché non ho la formula di y (x = valore temporale, y = prezzo), e ne ho bisogno per ottenere 1a e 2a derivata es, puoi spiegare? Grazie mille. Yaron – Yaron

+0

Quello che devi fare è eseguire la differenziazione numerica dei prezzi di chiusura livellati per determinare dy/dx: en.m.wikipedia.org/wiki/Numerical_differentiation. Quindi eseguire nuovamente la differenziazione per trovare d^2y/dx. Nota che ci sono altri modi più semplici per trovare i punti di svolta, controlla l'indicatore a zigzag: onlinetradingconcepts.com/TechnicalAnalysis/ZigZag.html –

3

Metto insieme un pacchetto che implementa linee di tendenza di supporto e resistenza come quello che stai chiedendo. Ecco alcuni esempi di alcuni esempi:

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

Output

Questo esempio solo tira i prezzi di chiusura corretti, ma se si dispone di dati intraday già caricati in voi può anche alimentare è dati grezzi come un array numpy e implementerà lo stesso algoritmo su quei dati come se lo si alimentasse con un simbolo ticker.

Non so se questo è esattamente quello che stavi cercando, ma spero che questo ti aiuti a iniziare. Il codice e qualche altra spiegazione possono essere trovati nella pagina GitHub dove l'ho ospitato: https://github.com/dysonance/Trendy

+0

Grazie! Lo proverò – Yaron

+0

Trova semplicemente i due valori più grandi e più piccoli e calcola le linee che passano da quei punti? – nurettin

+0

Per questa funzione specifica, trova il massimo e il minimo globali dei dati, quindi trova il 2 ° massimo e il massimo __esterno__ del periodo di finestra in cui lo si alimenta. Quindi se gli dai una finestra di 30 periodi, troverà il massimo/minimo più alto che è di almeno 30 periodi lontano dal massimo/minimo globale. Per prima cosa guarda avanti, ma se non ci sono ancora 30 periodi rimasti nella serie, allora guarderà indietro. Qui gli fornisco una finestra di 1.0/3.0, che interpreta come un terzo della lunghezza dei dati. Ci sono altri metodi che offrono approcci più flessibili se sei interessato :) –

8

Sto usando un algoritmo molto meno complesso nel mio sistema di trading algoritmico.

I passaggi seguenti sono un lato dell'algoritmo e vengono utilizzati per il calcolo dei livelli di supporto. Si prega di leggere le note sotto l'algoritmo per capire come calcolare i livelli di resistenza.

Algoritmo timeseries

  1. rompere in segmenti di dimensione N (diciamo, N = 5)
  2. Identificare valori minimi di ogni segmento, si avrà una matrice di valori minimi di tutti i segmenti =: arrayOfMin
  3. Find minimo (: arrayOfMin) =: minValue
  4. Vedere se uno dei valori rimanenti rientrano nella gamma (X% di: minValue) (Say, X = 1.3%)
  5. Fai un array separato (: supportArr)
    • aggiungere valori nel range & rimuovere questi valori da: arrayOfMin
    • anche aggiungere: minValue dal passaggio 3
  6. Calcolo supporto (o resistenza)

    • Prendere una media di questa matrice = support_level
    • Se il supporto viene testato molte volte, viene considerato valido.
    • strength_of_support = supportArr.length
    • level_type (SUPPORTO | RESISTENZA) = Ora, se il prezzo corrente è sotto il supporto quindi sostenere il ruolo cambia e diventa resistenza
  7. Ripetere i passaggi 3-7 fino a quando : arrayOfMin è vuoto

  8. Avrete tutti i valori di supporto/resistenza con una forza. Ora attenua questi valori, se i livelli di supporto sono troppo vicini, quindi elimina uno di essi.
  9. Questi supporti/resistenza sono stati calcolati considerando la ricerca dei livelli di supporto. È necessario eseguire i passaggi da 2 a 9 considerando la ricerca dei livelli di resistenza. Si prega di consultare le note e l'implementazione.

Note:

  • regolare i valori di N & X per ottenere risultati più accurati.
    • Esempio, per titoli meno volatili o indici azionari usa (N = 10, X = 1,2%)
    • Per stock volatile alti usare (N = 22, X = 1,5%)
  • Per la resistenza, la procedura è esattamente opposta (utilizzare la funzione massima invece del minimo)
  • Questo algoritmo è stato volutamente mantenuto semplice per evitare la complessità, può essere migliorato per ottenere risultati migliori.

Ecco la mia realizzazione:

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

principale classe calcolatrice

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

    } 

} 

Ecco alcune classi di supporto:

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

funziona bene? – experquisite

+1

Sì, funziona sicuramente. Ma non è perfetto, una volta compreso l'algoritmo, devi modificarlo per ottenere risultati sempre più accurati. Ti dà quella flessibilità. Prima prova a capire i passaggi, quindi ti consiglio di provarlo con i dati di borsa. Si prega di controllare la sezione "Note" della risposta. –

1

ho letto brevemente il contributo di Jacob.Penso che potrebbe avere alcuni problemi con il codice qui sotto: # Ora il min se min1 - Finestra < 0: min2 = min (x [(min1 + finestra):]) altro: min2 = min (x [ 0: (min1 - finestra)])

# 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 

l'algoritmo fa cercare di trovare valore min secondario finestra esterna proposta, ma poi la posizione corrispondente alla np.where (x == min2) [0] [0] potrebbe trovarsi all'interno della finestra a causa di possibili valori duplicati all'interno della finestra.

2

Ecco una funzione pitone per trovare support/resistance livelli

Questa funzione prende un allineamento NumPy di ​​ultimo prezzo negoziato e restituisce una lista di livelli di supporto e resistenza rispettivamente. n è il numero delle voci da scansionare.

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

E se volessi tracciare queste righe? Come troveresti le date corrispondenti? – cJc

+0

Immagino che puoi provare ad abbinare i prezzi supporto/resistenza ai dati originali, che dovrebbero includere un campo data. Ho tracciato questo prima, ma non riesco a ricordare il progetto! –