我有一个像这样的数据框:
close
formated
2017-01-03 09:30:00 29.9713
2017-01-03 09:31:00 29.0622
2017-01-03 09:32:00 29.0750
2017-01-03 09:33:00 29.0276
2017-01-03 09:34:00 29.0375
... ...
2022-08-19 09:30:00 173.5500
2022-08-19 09:31:00 173.4494
2022-08-19 09:32:00 173.3400
2022-08-19 09:33:00 173.3900
2022-08-19 09:34:00 173.2600
df 包含从 9:30 到 16:00 的每一分钟的价格值。 我希望每天的每一分钟都能获得最大可能的利润。
我目前正在做这样的事情:
df['Profit'] = (df.groupby(pd.Grouper(freq='D'))['close'].transform('max') - df['close']).div(df['close'])
这给出了每行的利润占当天最高值的百分比。
然而,这种方法是有缺陷的,因为它还会根据在达到当天最高值之后的时间戳来计算利润百分比。
但我不想要一整天的最大值,而是每天的最大值,仅包含我们当前正在查看的数据帧中的行之后的时间戳。
利润定义为该分钟的值与同一天随后所有分钟内的最大值之间的差值。
所需输出:
close Profit abs. Profit perc.
formated
2017-01-03 09:30:00 29.9713 0.0 0.0
2017-01-03 09:31:00 29.0622 0.0128 0.0004404
2017-01-03 09:32:00 29.0750 0.0 0.0
2017-01-03 09:33:00 29.0276 0.0099 0.0003410
2017-01-03 09:34:00 29.0375 0.0 0.0
... ... ... ...
请不要使用在 for 循环中迭代数据帧的解决方案,因为这非常慢。
最佳答案
您可以使用 pandas 的 cummax 函数来计算每天的累积最大值。但是,您需要反向应用它。
如果我们每小时这样做一次,为了解释:
>>> example_df
date price
2020-01-01 00:00 1
2020-01-01 01:00 2
2020-01-01 03:00 1
2020-01-01 04:00 7
2020-01-01 05:00 5
2020-01-01 06:00 2
2020-01-01 07:00 4
>>> example_df.reverse_cummax()
date price reverse_cummax
2020-01-01 00:00 1 7
2020-01-01 01:00 2 7
2020-01-01 03:00 1 7
2020-01-01 04:00 7 7
2020-01-01 05:00 5 5
2020-01-01 06:00 2 4
2020-01-01 07:00 4 4
这就是reverse_cummax函数的输出。
我们不能直接使用pandas中的cummax
,而且除了反转整个数据帧之外,没有简单的方法可以反转它。我们需要创建一个子函数来反转我们直接感兴趣的“分组依据”数据帧上的列的值,然后在完成后再次反转它们:
def reverse_cummax(df_day):
return df_day.loc[::-1, "close"].cummax()[::-1]
# This function produces a MultiLevelIndex, but we want our initial index
# back, so we need to drop a level
df["reverse_cummax"] = df.groupby(pd.Grouper(freq='D')).apply(reverse_cummax).droplevel(0)
然后,您可以通过将每个值减去即将到来的每日最大值(reverse_cummax
)来获得利润
df["profit abs"] = df["reverse_cummax"] - df["close"]
df["profit percentage"] = df["profit abs"]/df["close"]
已编辑以添加 dermen 建议的改进解决方案
关于Python:按天和当前时间戳计算最大利润,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73979825/