2017-01-28 82 views
1

将线性趋势拟合为一组数据非常简单。但是,我怎样才能将多条趋势线符合一个时间序列呢?我将上下趋势定义为高于或低于指数移动平均线的价格。当价格高于EMA时,我需要拟合一个积极的趋势,当趋势变为负向时,会出现一个新的负面趋势线等等。在我的代码下面,我的熊猫数据框中的market_data['Signal']告诉我趋势是在+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

我不知道我是否已经明白完全...因此,您希望为数据段创建多个线性拟合,每个线段都由'market_data ['Signal']'中的+1或-1定界,这是正确的吗? – 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很多为您的努力。请问两个问题。 1)图表中包含的所有market_data ['Close']值,或者只有符合连续信号条件的数据。我需要图表中的整个时间序列,尽管拟合仅适用于细分市场。 2)如何获取x轴上的日期? – cJc

+0

@cJc现在,所有'market_data ['Close']'被绘制(绿色和红色),并且拟合(黄色和蓝色)也覆盖整个X轴;也就是说,每个数据点都位于某个段内(并且每个段都会在发现'min_signal'个连续的非零相等值时开始)。如果您需要不同的东西,请尝试指定数据应该如何分段。 每个分段的日期仍在'segment.index'上。我使用'mdates.date2num'和'to_pydatetime'来转换日期,因为这是您最初在代码中使用的。 – jdehesa

+0

1)太好了。 2)我知道,因为numpy(和polyfit)不处理熊猫日期格式。 如何更改代码以在x轴上绘制日期? – cJc