2017-01-28 5 views
1

Die Anpassung eines linearen Trends an eine Datenmenge ist einfach. Aber wie kann ich mehrere Trendlinien an eine Zeitreihe anpassen? Ich definiere Trends als Preise über oder unter einem exponentiellen gleitenden Durchschnitt. Wenn der Preis über dem EMA liegt, muss ich einen positiven Trend anpassen und wenn der Trend negativ wird, eine neue negative Trendlinie und so weiter. In meinem Code unter der market_data['Signal'] in meinem Pandas Dataframe sagt mir, ob der Trend +1 oder -1 ist.Wie berechnet und plottet man mehrere lineare Trends für eine Zeitreihe?

Ich vermute, ich irgendeine Art einer Schleife müssen, aber ich kann die Logik nicht funktioniert ...

import pandas as pd 
import pandas_datareader.data as web 
import datetime as dt 
import numpy as np 
import matplotlib.pyplot as plt 
import matplotlib.patches as mpatches 
import matplotlib.dates as mdates 

#Colecting data 
market = '^DJI' 
end = dt.datetime(2016, 12, 31) 
start = dt.date(end.year-10, end.month, end.day) 
market_data = web.DataReader(market, 'yahoo', start, end) 

#Calculating EMA and difference 
market_data['ema'] = market_data['Close'].ewm(200).mean() 
market_data['diff_pc'] = (market_data['Close']/market_data['ema']) - 1 

#Defining bull/bear signal 
TH = 0 
market_data['Signal'] = np.where(market_data['diff_pc'] > TH, 1, 0) 
market_data['Signal'] = np.where(market_data['diff_pc'] < -TH, -1, market_data['Signal']) 

die Trendlinien passen I wan numpy polyfit verwenden

x = np.array(mdates.date2num(market_data.index.to_pydatetime())) 
fit = np.polyfit(x, market_data['Close'], 1) 

Idealerweise würde ich nur die Trends grafisch darstellen, wo das Signal mehr als n Perioden dauert.

Das Ergebnis sollte wie folgt aussehen:

enter image description here

+0

Ich bin mir nicht sicher, ob ich verstanden habe vollständig ... Sie wollen also mehrere lineare Anpassungen für Segmente der Daten erstellen, die jeweils durch +1 oder -1 in 'market_data ['Signal']' begrenzt sind. Ist das korrekt? – jdehesa

+0

Ja, das ist richtig. Im Idealfall nur wenn ich mehr als n +1 oder -1 hintereinander habe. – cJc

Antwort

2

hier eine Lösung. min_signal ist die Anzahl der aufeinander folgenden Signale in einer Zeile, die benötigt werden, um den Trend zu ändern. Ich importierte Seaborn eine besser aussehende Grundstück zu bekommen, aber es funktioniert alles das gleiche, ohne diese Zeile:

import pandas as pd 
import pandas_datareader.data as web 
import datetime as dt 
import numpy as np 
import matplotlib.pyplot as plt 
import matplotlib.patches as mpatches 
import matplotlib.dates as mdates 

#Colecting data 
market = '^DJI' 
end = dt.datetime(2016, 12, 31) 
start = dt.date(end.year-10, end.month, end.day) 
market_data = web.DataReader(market, 'yahoo', start, end) 

#Calculating EMA and difference 
market_data['ema'] = market_data['Close'].ewm(200).mean() 
market_data['diff_pc'] = (market_data['Close']/market_data['ema']) - 1 

#Defining bull/bear signal 
TH = 0 
market_data['Signal'] = np.where(market_data['diff_pc'] > TH, 1, 0) 
market_data['Signal'] = np.where(market_data['diff_pc'] < -TH, -1, market_data['Signal']) 


# Plot data and fits 

import seaborn as sns # This is just to get nicer plots 

signal = market_data['Signal'] 

# How many consecutive signals are needed to change trend 
min_signal = 2 

# Find segments bounds 
bounds = (np.diff(signal) != 0) & (signal[1:] != 0) 
bounds = np.concatenate(([signal[0] != 0], bounds)) 
bounds_idx = np.where(bounds)[0] 
# Keep only significant bounds 
relevant_bounds_idx = np.array([idx for idx in bounds_idx if np.all(signal[idx] == signal[idx:idx + min_signal])]) 
# Make sure start and end are included 
if relevant_bounds_idx[0] != 0: 
    relevant_bounds_idx = np.concatenate(([0], relevant_bounds_idx)) 
if relevant_bounds_idx[-1] != len(signal) - 1: 
    relevant_bounds_idx = np.concatenate((relevant_bounds_idx, [len(signal) - 1])) 

# Iterate segments 
for start_idx, end_idx in zip(relevant_bounds_idx[:-1], relevant_bounds_idx[1:]): 
    # Slice segment 
    segment = market_data.iloc[start_idx:end_idx + 1, :] 
    x = np.array(mdates.date2num(segment.index.to_pydatetime())) 
    # Plot data 
    data_color = 'green' if signal[start_idx] > 0 else 'red' 
    plt.plot(segment.index, segment['Close'], color=data_color) 
    # Plot fit 
    coef, intercept = np.polyfit(x, segment['Close'], 1) 
    fit_val = coef * x + intercept 
    fit_color = 'yellow' if coef > 0 else 'blue' 
    plt.plot(segment.index, fit_val, color=fit_color) 

Dies ist das Ergebnis:

Result

+0

Tnx viel für deine Bemühungen. Zwei Fragen pls. 1) Sind alle Werte für market_data ['Close'] in der Grafik enthalten, oder nur Daten, für die die Bedingung für aufeinander folgende Signale erfüllt ist. Ich brauche die ganze Zeitreihe in der Grafik, obwohl die Anpassung nur für die Segmente ist. 2) Wie bekomme ich die Daten auf der X-Achse zurück? – cJc

+0

@cJc Wie es jetzt ist, sind alle 'market_data ['Close']' (grün und rot) geplottet, und die Fits (in gelb und blau) decken auch die ganze X-Achse ab; das heißt, jeder Datenpunkt befindet sich innerhalb eines Segments (und jedes Segment beginnt, wenn "min_signal" aufeinanderfolgende ungleiche Werte gleich Null gefunden werden). Wenn Sie etwas anderes benötigen, versuchen Sie genau anzugeben, wie die Daten segmentiert werden sollen. Die Daten für jedes Segment befinden sich immer noch auf "segment.index". Ich habe 'mdates.date2num' und' to_pydatetime' verwendet, um die Daten zu konvertieren, da dies ursprünglich in Ihrem Code verwendet wurde. – jdehesa

+0

1) Großartig. 2) Ich weiß, weil numpy (und polyfit) Pandas Datumsformate nicht behandelt. Wie ändere ich den Code, um die Daten auf der x-Achse grafisch darzustellen? – cJc

Verwandte Themen