2011-12-21 9 views

Odpowiedz

44

Tak, bardzo prostym algorytmem jest wybór przedziału czasowego, powiedzmy 100 pasków, a następnie szukanie lokalnych punktów zwrotnych lub maksymalnych i minimalnych. Wartości Maxima i Minima można obliczyć na podstawie wygładzonej ceny zamknięcia za pomocą pierwszej i drugiej pochodnej (dy/dx i d^2y/dx). Gdzie dy/dx = zero i d^y/dx jest dodatnie, masz minima, kiedy dy/dx = zero, a d^2y/dx jest ujemne, masz maksima.

W praktyce można to obliczyć, wykonując iterację w oparciu o wygładzoną serię cen zamknięcia i patrząc na trzy sąsiednie punkty. Jeśli punkty są niższe/wyższe/niższe w kategoriach względnych, masz maksima, w innych wyższe/niższe/wyższe masz minimalne. Możesz chcieć dostroić tę metodę wykrywania, aby spojrzeć na więcej punktów (powiedzmy 5, 7) i wyzwalać tylko wtedy, gdy punkty brzegowe są określone% od punktu centralnego. jest to podobne do algorytmu, którego używa wskaźnik ZigZag.

Po osiągnięciu lokalnych maksimów i minimów, należy szukać skupisk punktów zwrotnych w pewnej odległości od siebie w kierunku Y. to jest proste. Weź listę N punktów zwrotnych i oblicz odległość Y między nią a każdym z odkrytych punktów zwrotnych. Jeśli odległość jest mniejsza niż stała stała, wówczas znaleziono dwa "zamknięte" punkty zwrotne, wskazujące możliwe wsparcie/opór.

Następnie można uszeregować linie S/R, więc dwa punkty zwrotne na 20 USD są mniej ważne niż na przykład trzy punkty zwrotne na 20 USD.

Rozszerzeniem tego byłoby obliczenie linii trendu. Z odkrytą listą punktów zwrotnych przyjmij teraz po kolei każdy punkt i wybierz dwa inne punkty, próbując dopasować równanie prostej. Jeśli równanie można rozwiązać w ramach określonego marginesu błędu, linia trendu jest nachylona. Jeśli nie, odrzuć i przejdź do następnej trójki punktów.

Powód, dla którego do wyliczania linii trendu potrzeba trzy razy, to dwa dowolne punkty w równaniu prostej. Innym sposobem obliczania linii trendu byłoby obliczenie równania prostej wszystkich par punktów zwrotnych, a następnie sprawdzenie, czy trzeci punkt (lub więcej niż jeden) leży na tej samej prostej w granicach błędu. Jeśli na tej linii leży 1 lub więcej innych punktów, bingo obliczyłeś linię trendu Wsparcia/Oporu.

Mam nadzieję, że to pomoże. Przykro mi, ale przykro mi, ale po prostu przedstawiam ci kilka pomysłów, jak to zrobić.W skrócie:

wejść do systemu

  • okres podsumowania L (ilość barów)
  • ceny zamknięcia dla barów L
  • Wygładzanie Factor (wygładzić cena zamknięcia)
  • margines błędu lub Delta (minimalna odległość między punktami zwrotnymi w celu dopasowania)

Wyjścia

  • listy punktów zwrotnych, połączenia ich tPoints [] (x, y)
  • Lista potencjalnych linii trendu, każdy z równania linii (y = mx + c)

Najlepsze chodzi,

+0

Dziękuję Andrew za swoje szczegółowa odpowiedź, zamierzam sprawdzić, czy – Yaron

+0

Cześć Andrew, sprawdziłem twój pomysł, wciąż nie mogę wymyślić jak obliczyć minima i maksima, ponieważ nie mam formuły y (x = wartość czasu, y = cena) i potrzebuję go, aby uzyskać pierwszą i drugą pochodną es, możesz wyjaśnić? Dziękuję Ci bardzo. Yaron – Yaron

+0

Co należy zrobić, to wykonać numeryczne zróżnicowanie wygładzonych cen zamknięcia, aby określić dy/dx: en.m.wikipedia.org/wiki/Numerical_differentiation. Następnie wykonaj ponownie różnicowanie, aby znaleźć d^2y/dx. Zauważ, że istnieją inne prostsze sposoby na znalezienie punktów zwrotnych, sprawdź wskaźnik zygzak: onlinetradingconcepts.com/TechnicalAnalysis/ZigZag.html –

3

Przygotowałem pakiet, który implementuje linie wsparcia i oporu, takie jak to, o co pytasz. Oto kilka przykładów kilka przykładów:

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

Output

Ten przykład tylko ciągnie zmienionych bliskie ceny, ale jeśli masz dane intraday już załadowane można również paszy surowe dane jako numpy tablicy i zaimplementuje ten sam algorytm na tych danych, jak gdyby po prostu nakarmił go symbolem ticker.

Nie jestem pewien, czy to dokładnie to, czego szukałeś, ale mam nadzieję, że to pomoże Ci zacząć. Kod i trochę więcej wyjaśnień można znaleźć na stronie GitHub, gdzie go hostuję: https://github.com/dysonance/Trendy

+0

Dzięki! Spróbuję. – Yaron

+0

Czy po prostu znajduje dwie największe i najmniejsze wartości i oblicza linie przechodzące z tych punktów? – nurettin

+0

W przypadku tej konkretnej funkcji znajduje globalną wartość maksymalną i minimalną danych, a następnie znajduje drugą pod względem maksimum i minę __outside__ okresu okna, który je podaje. Jeśli więc podasz mu okno z 30 okresami, znajdzie najwyższą wartość maksymalną/min, czyli co najmniej 30 okresów od globalnej wartości maksymalnej/min. Najpierw patrzy w przyszłość, ale jeśli w serii nie ma 30 okresów, to będzie wyglądać wstecz. Dostarczam tutaj okno 1.0/3.0, które interpretuje jako jedną trzecią długości danych. Istnieją inne metody, które zapewniają bardziej elastyczne podejście, jeśli jesteś zainteresowany :) –

8

Używam znacznie mniej złożonego algorytmu w moim systemie handlu algorytmicznego.

Następujące kroki są po jednej stronie algorytmu i służą do obliczania poziomów wsparcia. Przeczytaj uwagi poniżej algorytmu, aby zrozumieć, jak obliczyć poziomy oporu.

algorytm

  1. Przerwa timeseries na segmenty o rozmiarze N (powiedzmy, N = 5)
  2. Określić minimalną wartość każdego segmentu, będą mieć tablicę wartości minimalnych od wszystkich segmentów =: arrayOfMin
  3. Znajdź minimum (: arrayOfMin) =: minValue
  4. Sprawdź, czy którakolwiek z pozostałych wartości mieści się w zakresie (X% wartości: minimalna) (Powiedz, X = 1.3%)
  5. Dodać oddzielną tablicę (: supportArr)
    • dodawania wartości w zakresie & usunięcie tych wartości z: arrayOfMin
    • dodać: MINVALUE z etapu 3
  6. Obliczanie wspornik (lub odporność)

    • Take średnią tej tablicy = support_level
    • Jeśli wsparcie jest testowane wiele razy, wówczas jest uważane za silne.
    • strength_of_support = supportArr.length
    • level_type (wsparcie | ODPORNOŚĆ) = Teraz, jeśli aktualna cena jest poniżej wsparcia następnie wspieranie przemian rolę i staje Rezystancja
  7. Powtórz kroki od 3 do 7, aż : arrayOfMin jest pusty

  8. Będziesz miał wszystkie wartości wsparcia/wytrzymałości z siłą. Teraz wygładź te wartości, jeśli poziomy wsparcia są zbyt bliskie, a następnie wyeliminuj jeden z nich.
  9. Te wsparcie/opór zostały obliczone przy wyszukiwaniu poziomów wsparcia. Musisz wykonać kroki od 2 do 9, biorąc pod uwagę wyszukiwanie poziomów oporu. Zobacz uwagi i implementację.

Uwagi:

  • korygowania wartości N & X, aby uzyskać bardziej dokładne wyniki.
    • przykład, mniej lotnych udziałów lub indeksy kapitałowych użyć (n = 10 x = 1,2%)
    • Dla dużych zapasów lotnych użyć (n = 22 x = 1,5%)
  • W przypadku rezystancji procedura jest dokładnie odwrotna (użyj funkcji maksymalnej zamiast minimalnej).
  • Algorytm ten był celowo utrzymywany w stanie prostym, aby uniknąć złożoności, można go poprawić, aby uzyskać lepsze wyniki.

Oto moja realizacja:

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

Główna klasa kalkulator

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

    } 

} 

Oto niektóre zajęcia wspierające:

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

czy to działa dobrze? – experquisite

+1

Tak, to działa na pewno. Ale nie jest to doskonałe, kiedy zrozumiesz algorytm, musisz go dostosować, aby uzyskać coraz dokładniejsze wyniki. Daje to tę elastyczność. Najpierw spróbuj zrozumieć kroki, a następnie polecam wypróbowanie go z danymi o zapasach. Sprawdź sekcję "Uwagi" w odpowiedzi. –

1

pokrótce zapoznać wkład Jacoba.Myślę, że to może mieć pewne problemy z poniższym kodzie: # Teraz min jeśli MIN1 - okno < 0: min2 = min (x [(MIN1 + okno):]) else: min2 = min (x [ 0: (MIN1 - element)])

# 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 

algorytm musi spróbować znaleźć wtórnej wartości minimalnej na zewnątrz danego okna, ale w pozycji odpowiadającej np.where (x == min2) [0] [0] może leżeć w oknie z powodu możliwych duplikatów wartości w oknie.

2

Oto funkcja python znaleźć support/resistance poziom

Funkcja ta zajmuje numpy tablicę ostatniej ceny w obrocie i zwraca listę poziomów wsparcia i oporu odpowiednio. n to liczba wpisów do zeskanowania.

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

Co jeśli chcesz narysować te linie? Jak znaleźć odpowiednie daty? – cJc

+0

Sądzę, że możesz spróbować dopasować ceny wsparcia/rezystancji na oryginalnych danych, które powinny zawierać pole daty. Już to wykreśliłem, ale nie pamiętam projektu! –