EXPANSION OF THINKING IN INVESTMENT

투자에 대한 생각의 확장

CODING/PYTHON

[Python] 4주차_백테스팅 기초(1) : 골든/데드크로스 전략 구현 (2편) (Feat. 스파르타코딩클럽)

메타닷 2022. 12. 13. 14:07
728x90
반응형

 

4주차 2편에서는 

사는 시점(buy)과 파는 시점(sell)을 구해 

그 종가로 수익률을 구해보고, 

장/단기 이평선을 적용시킨 수익률을 구한 후, 

최적의 장/단기 이평선을 구하는 내용을 배웠다. 

 

복잡하고 어려운 내용들로 가득해서, 

천천~히 여러번 반복해봐야겠다. 

 

6. 수익률 구하기 

1) 실제로 사는 시점(buy)

  - buy > buy > buy 혹은 sell > sell > sell 이라면, 사거나 파는게 아니다. 
  - 즉, buy와 sell이 바뀌는 순간이 중요하다.

  - action_temp라는 열을 만들고, action 값들을 한칸씩 뒤로 밀어 넣는다. 그러면 buy와 sell이 바뀌는 부분을 확인할 수 있다. 

df['action_temp'] = df['action'].shift(1)

[실제로 사는 시점 구하기1]

 

  - 위와 같은 조건에 부합하는 cond을 만들어 본다. 

cond = (df['action'] == 'buy') & (df['action'].shift(1) == 'sell')
df['real_buy'] = np.where(cond,'buy','')
df

[실제로 사는 시점 구하기2]

   
  - 사는 날짜(buy)를 모아본다.

cond1 = (df['action'] == 'buy') & (df['action'].shift(1) == 'sell')

df[cond]

[실제로 사는 시점 모아보기]


2) 실제로 파는 시점(sell)

  - 사는 시점을 모으는 것과 마찬가지로 cond2를 만들어 파는 시점(sell)을 모아본다. 

cond1 = (df['action'] == 'buy') & (df['action'].shift(1) == 'sell')
cond2 = (df['action'] == 'sell') & (df['action'].shift(1) == 'buy')

df_sell = df[cond2]

df_sell

[실제로 파는 시점 모아보기]


3) 마지막 시점에서 무조건 팔기

  - 마지막에 팔아야 수익율을 알 수 있다

df = fdr.DataReader('005930','2018')

df = df[['Close']]
df['ma'] = df.rolling(3).mean().shift(1)
df['action'] = np.where(df['Close'] > df['ma'], 'buy', 'sell')

df.iloc[-1,-1] = 'sell'

cond1 = (df['action'] == 'buy') & (df['action'].shift(1) == 'sell')
cond2 = (df['action'] == 'sell') & (df['action'].shift(1) == 'buy')

df_buy = df[cond1]
df_sell = df[cond2]

[마지막 시점에서 무조건 팔기]


4) 사고, 파는 시점을 붙이기

  - `concat` 을 이용하면 되는데, 가로로 붙이려면 `,axis=1`를 써준다. 

df_result = pd.concat([df_buy,df_sell],axis=1)

df_result

[사고, 파는 시점 붙이기]


5) 전략 세워보기

  - buy 때 사서, sell에 파는 것인데, 더 쉽게 보기 위해 .reset_index()를 이용해 가로로 붙여본다. 
  - buy 때의 Close와 sell 때의 Close 에 주목하면 된다.

df_buy = df[cond1].reset_index()
df_sell = df[cond2].reset_index()

df_result = pd.concat([df_buy,df_sell],axis=1)

df_result

[사고, 파는 시점 옆으로 붙여보기]

 

6) 수익률 구하기

  - 먼저, 헷갈리지 않도록 Close라는 컬럼명을 다르게 수정해준다.
  - 그리고, `수익률 = 종가(sell) / 종가(buy)` 를 추가해준다.

df_buy = df[cond1].reset_index()
df_buy.columns = ['날짜','종가(buy)','이평값','액션']
df_sell = df[cond2].reset_index()
df_sell.columns = ['날짜','종가(sell)','이평값','액션']

df_result = pd.concat([df_buy,df_sell],axis=1)
df_result['수익률'] = df_result['종가(sell)'] / df_result['종가(buy)']

df_result

[수익률 구하기]


7) 오류 해결하기

  - 기존 dataframe을 건드리지 않고 수익률을 가져오기 위해 .copy()를 써준다. 

df = df[['Close']].copy()

[오류 해결을 위해 .copy() 붙이기]


8) 누적 수익률 계산하기

  - .cumprod()를 입력하면 누적 곱을 볼 수 있다.

df_result[['수익률']].cumprod()

[누적 수익률 계산하기]


 - 누적 곱의 마지막 값(수익률)을 가져온다. 

df_result[['수익률']].cumprod().iloc[-1,-1]

[최종 수익률 가져오기]


  -  1(원금)을 빼주고 100을 곱해주면 수익률(%)이 나온다.

(df_result[['수익률']].cumprod().iloc[-1,-1] - 1)*100

[수익률(%) 만들어 보여주기]


9) 함수로 만들기

  - 코드만 입력하면 될 수 있도록 함수로 만들어본다. 

  - get_return(code,n) 에 기업 코드와 기준일을 넣어, 수익률이 얼마인지 확인해본다. 

def get_return(code,n):
  df = fdr.DataReader(code,'2018')

  df = df[['Close']].copy()
  df['ma'] = df.rolling(n).mean().shift(1)
  df['action'] = np.where(df['Close'] > df['ma'], 'buy', 'sell')

  df.iloc[-1,-1] = 'sell'

  cond1 = (df['action'] == 'buy') & (df['action'].shift(1) == 'sell')
  cond2 = (df['action'] == 'sell') & (df['action'].shift(1) == 'buy')

  df_buy = df[cond1].reset_index()
  df_buy.columns = ['날짜','종가(buy)','이평값','액션']
  df_sell = df[cond2].reset_index()
  df_sell.columns = ['날짜','종가(sell)','이평값','액션']

  df_result = pd.concat([df_buy,df_sell],axis=1)
  df_result['수익률'] = df_result['종가(sell)'] / df_result['종가(buy)']

  return df_result[['수익률']].cumprod().iloc[-1,-1] - 1

 

[함수로 만들어, 다른 기업 적용해보기]

 

7. 단기/장기이평선 적용하기 

1) 단기/장기이평선 구하기

  - rolling의 숫자를 3일(단기) , 10일(장기)로 지정해준다. 

df = fdr.DataReader('005930','2018')

df = df[['Close']].copy()

df['ma_1'] = df['Close'].rolling(3).mean().shift(1)
df['ma_2'] = df['Close'].rolling(10).mean().shift(1)

df

 

[단기/장기이평선 구하기]


2) 적절한 값으로 수정하기

  - Close, ma_1, ma_2 를 고려하여 컬럼값을 추가해준다. 

df = fdr.DataReader('005930','2018')

df = df[['Close']].copy()

df['ma_1'] = df['Close'].rolling(3).mean().shift(1)
df['ma_2'] = df['Close'].rolling(10).mean().shift(1)

df['action'] = np.where(df['ma_1'] > df['ma_2'], 'buy', 'sell')

df.iloc[-1,-1] = 'sell'

cond1 = (df['action'] == 'buy') & (df['action'].shift(1) == 'sell')
cond2 = (df['action'] == 'sell') & (df['action'].shift(1) == 'buy')

df_buy = df[cond1].reset_index()
df_buy.columns = ['날짜','종가(buy)','이평값1','이평값2','액션']

df_sell = df[cond2].reset_index()
df_sell.columns = ['날짜','종가(sell)','이평값1','이평값2','액션']

df_result = pd.concat([df_buy,df_sell],axis=1)

df_result['수익률'] = df_result['종가(sell)'] / df_result['종가(buy)']
df_result

   

[단기/장기이평선 구하고 컬럼값 추가하기]

 

  - 수익률의 마지막 값을 .tail(1)로 바꾸어 주고, 단기·장기 컬럼을 만들어준다.

df_final = (df_result[['수익률']].cumprod().tail(1) - 1)*100
df_final['단기'] = 3
df_final['장기'] = 10

df_final

[특정 단기, 장기이평선의 수익률 확인하기]


3) 함수로 만들기

  - 함수로 만들고, code, short, long 값만 바꿔주면 된다.

  - 그러면 기업의 단기, 장기 기준일을 정해서 수익률을 확인할 수 있다. 

def get_return_sl(code, short, long):
  df = fdr.DataReader(code,'2018')

  df = df[['Close']].copy()

  df['ma1'] = df['Close'].rolling(short).mean().shift(1)
  df['ma2'] = df['Close'].rolling(long).mean().shift(1)

  df['action'] = np.where(df['ma1'] > df['ma2'], 'buy', 'sell')

  df.iloc[-1,-1] = 'sell'

  cond1 = (df['action'] == 'buy') & (df['action'].shift(1) == 'sell')
  cond2 = (df['action'] == 'sell') & (df['action'].shift(1) == 'buy')

  df_buy = df[cond1].reset_index()
  df_buy.columns = ['날짜','종가(buy)','이평값1','이평값2','액션']

  df_sell = df[cond2].reset_index()
  df_sell.columns = ['날짜','종가(sell)','이평값1','이평값2','액션']

  df_result = pd.concat([df_buy,df_sell],axis=1)

  df_result['수익률'] = df_result['종가(sell)'] / df_result['종가(buy)']

  df_final = (df_result[['수익률']].cumprod().tail(1) - 1)*100
  df_final['단기'] = short
  df_final['장기'] = long

  return df_final

[기업의 단기, 장기 기준일을 정해서 수익률 확인하기]

 

4) 한 종목에 대한 최적의 단기/장기이평선 구하기

  - for문을 이용해서 최적의 단/장기 이평선과 수익률을 구해본다.

[최적의 단/장기 이평선과 수익률 구하기]

 

 

728x90
반응형