2017-01-28 12 views
1

Установка линейного тренда к набору данных прямолинейна. Но как я могу поместить несколько линий тренда в один временной ряд? Я определяю тенденции вверх и вниз как цены выше или ниже экспоненциальной скользящей средней. Когда цена выше EMA, мне нужно установить положительную тенденцию, и когда тренд станет отрицательным, новая отрицательная трендовая линия и так далее. В моем коде ниже market_data['Signal'] в моей кадре данных pandas мне сообщается, что тренд вверх +1 или вниз -1.Как рассчитать и построить несколько линейных трендов для временного ряда?

Я предполагаю, что мне нужно какое-то цикл, но я не могу работать логика ...

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']) 

Чтобы соответствовать линии тренда я Вана использовать Numpy polyfit

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

В идеале я хотел бы только строить тенденции, когда сигнал длится больше, чем n периодов.

Результат должен выглядеть примерно так:

enter image description here

+0

Я не уверен, если я понял полностью ... Итак, вы хотите создать несколько линейных приемов для сегментов данных, каждая из которых ограничена +1 или -1 в 'market_data ['Signal']', это правильно? – jdehesa

+0

Да, это правильно. Идеально только тогда, когда у меня больше n +1 ot -1 подряд. – cJc

ответ

2

Вот решение. min_signal - это количество последовательных сигналов в строке, которые необходимы для изменения тренда. Я импортировал Seaborn, чтобы получить более красивый сюжет, но он всё равно работает без этой строки:

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) 

Это результат:

Result

+0

Tnx много для ваших усилий. Два вопроса pls. 1) Все значения для market_data ['Close'] включены в график или только данные, для которых выполняется условие последовательных сигналов. Мне нужен весь временной ряд на графике, хотя фитинг - только для сегментов. 2) Как мне получить даты на оси х? – cJc

+0

@cJc Как это прямо сейчас, все 'market_data [«Close»] 'строится (в зеленый и красный), и припадки (в желтый и синий) покрывают всю ось X тоже; то есть каждая точка данных находится внутри некоторого сегмента (и каждый сегмент начинается, когда найдены «min_signal» последовательные ненулевые равные значения). Если вам нужно что-то другое, попробуйте точно указать, как данные должны быть сегментированы. Даты для каждого сегмента по-прежнему находятся на 'segment.index'. Я использовал 'mdates.date2num' и' to_pydatetime', чтобы преобразовать даты, потому что это то, что вы использовали в своем коде изначально. – jdehesa

+0

1) Отлично. 2) Я знаю, потому что numpy (и polyfit) не обрабатывает форматы даты pandas. Как изменить код, чтобы начертить даты на оси х? – cJc