80

我有一个 OHLC 价格数据集,我已将其从 CSV 解析为 Pandas 数据框并重新采样到 15 分钟柱:

<class 'pandas.core.frame.DataFrame'>
DatetimeIndex: 500047 entries, 1998-05-04 04:45:00 to 2012-08-07 00:15:00
Freq: 15T
Data columns:
Close    363152  non-null values
High     363152  non-null values
Low      363152  non-null values
Open     363152  non-null values
dtypes: float64(4)

我想添加各种计算列,从简单的列开始,例如周期范围 (HL),然后是布尔值以指示我将定义的价格模式的出现 - 例如锤形蜡烛模式,其示例定义:

def closed_in_top_half_of_range(h,l,c):
    return c > l + (h-l)/2

def lower_wick(o,l,c):
    return min(o,c)-l

def real_body(o,c):
    return abs(c-o)

def lower_wick_at_least_twice_real_body(o,l,c):
    return lower_wick(o,l,c) >= 2 * real_body(o,c)

def is_hammer(row):
    return lower_wick_at_least_twice_real_body(row["Open"],row["Low"],row["Close"]) \
    and closed_in_top_half_of_range(row["High"],row["Low"],row["Close"])

基本问题:如何将函数映射到列,特别是在我想引用多个其他列或整行或其他什么的地方?

这篇文章处理从单个源列中添加两个计算列,这很接近,但并不完全如此。

并且稍微高级一点:对于参考不止一根柱线 (T) 确定的价格模式,我如何从函数定义中参考不同的行(例如 T-1、T-2 等)?

4

4 回答 4

77

对于您想要执行的每一列,确切的代码会有所不同,但您可能希望使用mapandapply函数。在某些情况下,您可以直接使用现有列进行计算,因为这些列是 Pandas Series 对象,它们也可以用作 Numpy 数组,它会自动按元素进行通常的数学运算。

>>> d
    A   B  C
0  11  13  5
1   6   7  4
2   8   3  6
3   4   8  7
4   0   1  7
>>> (d.A + d.B) / d.C
0    4.800000
1    3.250000
2    1.833333
3    1.714286
4    0.142857
>>> d.A > d.C
0     True
1     True
2     True
3    False
4    False

如果您需要在一行中使用诸如 max 和 min 之类的操作,您可以使用applywithaxis=1将您喜欢的任何函数应用于每一行。这是一个计算的例子min(A, B)-C,它看起来就像你的“下灯芯”:

>>> d.apply(lambda row: min([row['A'], row['B']])-row['C'], axis=1)
0    6
1    2
2   -3
3   -3
4   -7

希望这能让您对如何继续进行一些了解。

编辑:要将行与相邻行进行比较,最简单的方法是对要比较的列进行切片,省略开头/结尾,然后比较结果切片。例如,这将告诉您 A 列中的元素在哪些行中小于 C 列中下一行的元素:

d['A'][:-1] < d['C'][1:]

而这会以另一种方式进行,告诉您哪些行的 A 小于前一行的 C:

d['A'][1:] < d['C'][:-1]

['A"][:-1]对 A 列的最后一个元素进行切片['C'][1:],并对 C 列的第一个元素进行切片,因此,当您将这两者对齐并比较它们时,您将 A 中的每个元素与下一行中的 C 进行比较。

于 2012-09-11T20:04:56.837 回答
48

您可以is_hammerrow["Open"]等方面如下

def is_hammer(rOpen,rLow,rClose,rHigh):
    return lower_wick_at_least_twice_real_body(rOpen,rLow,rClose) \
       and closed_in_top_half_of_range(rHigh,rLow,rClose)

然后你可以使用地图:

df["isHammer"] = map(is_hammer, df["Open"], df["Low"], df["Close"], df["High"])
于 2012-09-11T20:04:39.830 回答
5

对于问题的第二部分,您也可以使用shift,例如:

df['t-1'] = df['t'].shift(1)

t-1然后将包含 t 上面一行的值。

http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.shift.html

于 2014-08-16T12:52:19.723 回答
1

您列出的前四个函数也适用于向量,但需要调整 lower_wick 除外。像这样的东西,

def lower_wick_vec(o, l, c):
    min_oc = numpy.where(o > c, c, o)
    return min_oc - l

其中 o、l 和 c 是向量。您可以这样做,而不是将 df 作为输入并避免使用 numpy,尽管它会慢得多:

def lower_wick_df(df):
    min_oc = df[['Open', 'Close']].min(axis=1)
    return min_oc - l

其他三个将按原样处理列或向量。然后你可以完成

def is_hammer(df):
    lw = lower_wick_at_least_twice_real_body(df["Open"], df["Low"], df["Close"]) 
    cl = closed_in_top_half_of_range(df["High"], df["Low"], df["Close"])
    return cl & lw

&位运算符可以对布尔向量、 for and|for等执行集合逻辑or。这足以完全向量化您提供的样本计算,并且应该相对较快。通过在执行这些计算时临时使用数据底层的 numpy 数组,您可能会加快速度。

对于第二部分,我建议引入一列来指示每一行的模式,并编写一系列处理每种模式的函数。然后按模式分组并将适当的功能应用于每个组。

于 2015-03-05T15:35:00.297 回答