如何在Python中创建简单的标志

时间:2019-07-25 12:54:42

标签: python pandas trading algorithmic-trading

从Yahoo获得SPY数据后,我使用最大和最小滚动窗口创建收盘价通道,如下所示。列是HC和HL。

我需要创建一个列(我称之为标记),当收盘价等于HC时该列显示1,并且该值一直持续到收盘价等于HL为止。此时,Flag的值为-1。如您所见,这很简单,Flag只能有两个值; 1或-1。

简单的公式如下:

  1. 如果Close == HC,则标志为1
  2. 如果Close == HL,则标志为-1
  3. 如果Close!= HC和Close!= HL,则标志等于变量标志上保存的最后一个值。

我尝试了好几件事,包括下面的代码,但没有碰到运气。此代码的问题是显示0值。而且我不知道如何使其通过条件消失:

import pandas as pd
import pandas_datareader as dr
import numpy as np
from datetime import date

df = dr.data.get_data_yahoo('SPY',start='01-01-2019',end=date.today())

df['HC'] = df['Close'].rolling(20).max() 
df['LC'] = df['Close'].rolling(20).min() 

df['Flag'] = [1 if (df.loc[ei, 'Close'] == df.loc[ei, 'HC']) else 
              -1 if (df.loc[ei, 'Close'] == df.loc[ei, 'LC']) else   
              0 for ei in df.index]

在下面,您可以以蓝色看到我的代码的结果,并以红色看到我需要的结果。

Image

有没有简单的方法可以做到这一点?如果有人可以帮助我,我将不胜感激。谢谢!

3 个答案:

答案 0 :(得分:3)

尽管已经回答了这个问题,但是计算这种结果的最快方法通常是使用np.where,如下所示:

import pandas as pd
import pandas_datareader as dr
import numpy as np
from datetime import date

df = dr.data.get_data_yahoo('SPY',start='01-01-2019',end=date.today())

df['HC'] = df['Close'].rolling(20).max() 
df['LC'] = df['Close'].rolling(20).min() 

下面有一个嵌套的逻辑:

  1. 创建一个空数组
  2. 在条件下用-1替换值
  3. 在条件下用1替换值
df['Flag'] = np.where((df.Close == df.HC), 1, 
         np.where(df.Close == df.LC, -1, np.full(df.Close.count(), np.nan)))
df.Flag.fillna(method='ffill', inplace=True)

在性能方面:

%%timeit
df['Flag'] = np.where((df.Close == df.HC), 1, 
         np.where(df.Close == df.LC, -1, np.full(df.Close.count(), np.nan)))
df.Flag.fillna(method='ffill', inplace=True)
912 µs ± 49.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

如果有条件,循环或嵌套绝对更好。

例如@Tim Mironov答案:

%%timeit
pos_indexes = (df.Close == df.HC)
neg_indexes = (df.Close == df.LC)

df.loc[pos_indexes, 'Good_Flag'] = 1
df.loc[neg_indexes, 'Good_Flag'] = -1

df.fillna(method='ffill', inplace=True)
4.43 ms ± 92 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

答案 1 :(得分:2)

您可以使用Pandas的更多内置功能,特别是fillna方法和逻辑索引的用法。 我已在原始代码中添加了一部分代码,以创建其他Good_Flag

import pandas_datareader as dr
from datetime import date

df = dr.data.get_data_yahoo('SPY',start='01-01-2019',end=date.today())

df['HC'] = df['Close'].rolling(20).max() 
df['LC'] = df['Close'].rolling(20).min() 

df['Flag'] = [1 if (df.loc[ei, 'Close'] == df.loc[ei, 'HC']) else 
              -1 if (df.loc[ei, 'Close'] == df.loc[ei, 'LC']) else   
              0 for ei in df.index]

pos_indexes = df.Close == df.HC
neg_indexes = df.Close == df.LC
df.loc[pos_indexes, 'Good_Flag'] = 1
df.loc[neg_indexes, 'Good_Flag'] = -1
df = df.fillna(method='ffill')

请注意,我使用fillna属性的ffill方法来指定“转发通行证”。

编辑: 为了明确起见,原始的Flag列留在此处是有意的,而新的Good_Flag列的计算不依赖于Flag

展示理想的行为:

plt.plot(df.Flag, color='blue')
plt.plot(df.Good_Flag, color='red')
plt.legend(['Flag', 'Good_Flag'])
plt.show()

enter image description here

答案 2 :(得分:0)

一种简单的方法是使用循环,但这在时间方面效率低下。但是,如果您不介意,则可以遍历数组

flag01 = 0
for ei in df.index:
    if (df.loc[ei, 'Close'] == df.loc[ei, 'HC']):
        flag01 = 1
    if (df.loc[ei, 'Close'] == df.loc[ei, 'LC'])
        flag01 = -1
    df.loc[ei, 'Flag'] = flag01

基本上,您设置为零,只要发现条件为true,就将其设置为1并保持1,直到满足条件成为-1,依此类推。这比您使用的方法要慢,但是这是“保留最后一个值”的最简单方法,因为您要增加值并知道以前拥有哪个值。