今天在实习中遇到了这样一个问题,对我来说有点复杂,连起标题都不知道该怎么起,拿来记录一下。
问题是这样的,有一个DataFrame,以日期为index,value值是一个有正有负的Series。
data = {
'Date': ['2023-07-01', '2023-07-02', '2023-07-03', '2023-07-04', '2023-08-02', '2023-08-03', '2023-08-04'],
'Values': [0.03, -0.02, -0.03, 0.01, 0.0, 0.01, 0.03]
}
df = pd.DataFrame(data)
我是做量化的,value值代表了根据我的策略买股票每日的收益率。为此我的目标是设置一个每月止损率,比如当我亏了0.04的时候,我就需要在当月出来,下个月再进入。所以我希望得到的是将每个月第一个小于止损率(-0.04)的组合,将组合中前面所有的值改为0,最后一个值直接改为止损率-0.04,将组合后当月数据也改为0。这样我预计得到的数组应该是 [0.03, 0, -0.04, 0, 0, 0.01, 0.03]。
话不多说,只要自己能看懂就可以哈哈,我的代码是这样的:
def findStop(df, col, stop_value=-0.0025):
new_df = pd.DataFrame()
for _, group_df in df.groupby(df.index.month): # 按照月份将dataframe分开
dp, idx = 1000, 0 # dp记录最大亏损,初设为一个很大的值
group_df = group_df.reset_index(drop=True)
mem = [0, 0] # mem记录亏损开始位置和结束位置
for i in range(1, len(group_df)+1):
if dp >= 0:
idx = i-1;
dp = min(dp, 0) + group_df.iat[i-1, 0]
if dp <= stop_value: # 当最大亏损超过止损率,跳出循环
mem[0] = idx
mem[1] = i-1
break
if mem[0] + mem[1] != 0: # 如果当月没有亏超过亏损率的,不改变数值
# 将亏损其他位置设为0
group_df.loc[mem[0]:mem[1], col] = 0
# 将亏损最后一个值置为stopvalue
group_df.loc[mem[1], col] = stop_value
# 将亏损后当月其他值设为0
group_df.loc[mem[1]+1: len(group_df), col] = 0
new_df = pd.concat([new_df, group_df]) # 将所有月份汇集到新的dataframe中
return new_df[col].tolist()
结果如预期一样,得到:
当然,如果不是dataframe也很好做,只要稍微改一改就可以了