<jupyter_start><jupyter_text>references : http://nbviewer.jupyter.org/gist/FinanceData/d32ee2d58d760588669494407391b241<jupyter_code>import pandas as pd
import matplotlib.pylab as plt
%matplotlib inline
import numpy as np
def korean_stock_data_is_mine(how_much_page ,stock_code):
    '''
    how_much_page : 원하는 페이지만큼의 데이터를 가지고 옵니다. 50개의 페이지가 넘어갈 때마다 알림이 나옵니다.
    페이지 하나 당, 주말 포함 10일의 데이터가 있습니다.
    
    stock_code : 아래의 주석에 나와있는 코드
를 string으로 넣어주시면 됩니다.
    
    ***stock_code는 아래의 링크를 참조하시기 바랍니다.
    http://bigdata-trader.com/itemcodehelp.jsp
    ***
    
    output // 주말의 결측치가 제거된 데이터 프레임이 나옵니다. 컬럼 정보로는
    날짜 , 종가 , 전일비 , 시가 , 고가 , 저가 , 거래량 이 됩니다.
    '''
    final_df = pd.DataFrame(columns=[0, 1, 2, 3, 4, 5, 6])

    for page in range(1,how_much_page+1) :
        try : 
            if page % 50 == 0 : print('{} th is done.'.format(page))

            url = 'http://finance.naver.com/item/sise_day.nhn?code={}&page={}'.format(stock_code,page)
            df = pd.read_html(url)[0]
            df = df.iloc[1:,:]
            final_df = pd.concat([final_df,df],axis=0)
        except : break ; print('{}th data is list data'.format(page))
            
    final_df.rename(columns={0:'날짜',1:'종가',2:'전일비',3:'시가',4:'고가',5:'저가',6:'거래량'},inplace=True)
    final_df.dropna(axis=0,inplace=True)
    final_df.reset_index(drop=True,inplace=True)

    return final_df
%matplotlib inline
import matplotlib.pyplot as plt
import matplotlib
matplotlib.rc('figure', figsize=(16, 4))
import datetime
import pandas as pd
import FinanceDataReader as fdr
start = datetime.datetime(2016, 1, 1)
end = datetime.datetime(2016, 12, 31)

# KB금융(105560)
df = fdr.DataReader("035720", start, end)
df = df[df.Volume > 0]
df.head()<jupyter_output><empty_output><jupyter_text>라인 차트 - 가격<jupyter_code># 가격 Close
df['Close'].plot(figsize=(16, 4), title='KaKao')<jupyter_output><empty_output><jupyter_text>라인 차트 - 거래량<jupyter_code>plt.subplot(211)
plt.title ('Volume')
plt.plot(df['Volume'], color='g')
plt.subplot(212)
plt.bar(df.index.to_pydatetime(), df['Volume'], color='g')
plt.show()<jupyter_output><empty_output><jupyter_text>이동평균- 활용    - 이동평균 : 특정 구간의 평균치를 이은 선 (구간 : 시계열적 구간)    - 주가의 불규칙성을 완화하는 데 사용- 기간별 분류     - 장기일 수록 추세는 정확하나 후행성이 커짐        - 단기추세 : 5일        - 중기추세 : 20,60        - 장기추세 : 120,200<jupyter_code>df['MA_5'] = df['Close'].rolling(window=5).mean() # 단기추세
df['MA_20'] = df['Close'].rolling(window=20).mean() # 중기추세
df.dropna().head()<jupyter_output><empty_output><jupyter_text>플롯으로 추세 적용치를 확인해본다.<jupyter_code>df[['Close', 'MA_5', 'MA_20']].plot()<jupyter_output><empty_output><jupyter_text>마지막 구간을 확대- window 구간이 커질 수록, 변동성이 작아지면서 추세성 반영률이 높아지지만, 후행성이 높아지는 것을 볼 수 있다.<jupyter_code>df[['Close', 'MA_5', 'MA_20']].head(100).plot()<jupyter_output><empty_output><jupyter_text>이동평균선 분석법 정배열과 역배열- 정배열 : 하단부터 장기, 중기, 단기 이동평균 선이 존재 (상승국면)- 역배열 : 하단부터 단기, 중기, 장기 이동평균 선이 존재 (하락국면) 추세 전환- "단기 → 장기"순으로 주가의 이동평균값이 움직임 골든크로스, 데드크로스- 골든크로스(Golden cross)    - 단기이동평균선이 중장기이동평균선을 상향돌파(크로스)하는 것.    - 즉, 5일선이 20일선을, 20일선이 60일선을, 60일선이 120일선을 돌파할 때- 데드크로스 (Dead cross)    - 단기 이동평균선이 중장기이동평균선을 하향돌파 하는 것    - 즉, 5일선이 20일선을, 20일선이 60일선을, 60일선이 120일선을 하향 돌파- 계산법    - 단기와 장기 이동평균의 차이값(MA_5 - MA_20)를 비교    - 크로스(즉, 이전 값과 부호가 바뀌는 경우): (차이값 X 이전 차이값) < 0<jupyter_code>df['diff'] = df['MA_5'] - df['MA_20']
df['diff'].dropna().plot()
#  (이전 차이값 X 차이값 ) < 0: 이전 값과 부호가 바뀐 경우 
cross = df['diff'].shift(1) * df['diff'] < 0 # cross 는 True or False 의 형태로 반환된다.
df['diff'][cross == True]

# 'cross' 컬럼을 추가하여, diff의 부호가 이전과 달라지는 경우 각각 저장
# 이때, 현재 diff > 0 이면, 골든 크로스, diff < 0 이면, 데드 크로스, 
df['cross'] = ''
df.loc[(df['diff'].shift(1) * df['diff'] < 0) & (df['diff'] > 0), 'cross'] = 'golden'
df.loc[(df['diff'].shift(1) * df['diff'] < 0) & (df['diff'] < 0), 'cross'] = 'dead'

# 부호가 달라지면 : (df['diff'].shift(1) * df['diff'] < 0) & (df['diff'] < 0)
# cross 컬럼에다가 : , 'cross'
# df 데이터프레임의 cross 컬럼에 golden or dead 라는 문구를 넣어라 : df.loc // golden | dead
df[df['cross'] != '']
#signal이 발생한 컬럼
ax = df[['Close', 'MA_5', 'MA_20']].plot(figsize=(16,6))
prev_key = prev_val = 0

for key, val in df['diff'].iteritems():
    if val == 0:
        continue

    if val * prev_val < 0 and val > prev_val:
        ax.annotate('Golden', xy=(key, df['MA_20'][key]), xytext=(10,-30), 
                    textcoords='offset points', arrowprops=dict(arrowstyle='-|>'))
    elif val * prev_val < 0 and val < prev_val:
        ax.annotate('Dead', xy=(key, df['MA_20'][key]), xytext=(10,30), 
                    textcoords='offset points', arrowprops=dict(arrowstyle='-|>'))
        
    prev_key, prev_val = key, val
import numpy as np
signal_ls = [i for i in df['cross']]
signal_ls = [np.nan if not i else i for i in signal_ls ]
df['Signal'] = signal_ls
df.fillna(method='ffill',inplace=True)
bt_df = df.dropna()
bt_df.tail()
bt_df['bt_return'] = [bt_df['return'][idx] if bt_df['Signal'][idx] == 'golden' else 2-(bt_df['return'][idx]) for idx in range(len(bt_df))]
bt_df.head()
from functools import reduce
np.round(bt_df['bt_return'].cumprod()[-1],2)
df.tail()
plt.plot(df['return'].cumprod(),label='bnh')
plt.plot(bt_df['bt_return'].cumprod(),label='mine')
plt.legend() ; plt.grid()<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.176459219172787, 'fraction_numerical': 0.0363355237727097, 'mean_word_length': 3.863721804511278, 'pattern_counts': {'":': 0, '<': 41, '<?xml version=': 0, '>': 35, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '7', 'dir': 'jupyter-structured-clean-dedup', 'id': '514543', 'license': 'MIT', 'n_tokens_mistral': 2822, 'n_tokens_neox': 3127, 'n_words': 497, 'path': 'SSU/trading_exercise/Moving_Average_strategy.ipynb', 'repo_name': 'hskimim/Quantitative_Finance', 'size': '5174'}