TradeOptimizer의 '볼린저밴드 트레이드-Ver01' 전략을 소개합니다. 결과부터 이야기하면, 특정 종목 두 세개를 살펴봤을때, 현재 시점으로는 좋은 전략으로 보이지는 않습니다. 더 좋은 전략이 될 수 있도록 로직 수정을 고려할 필요가 있습니다.

 

본격적인 설명에 앞서 아래 내용을 주의해주세요.

 

  • 특정 종목 추천하거나 투자를 권장하려는 글이 아닙니다. 트레이딩 기술에 대한 일반적인 소개 글입니다.
  • 과거의 데이터가 미래의 결과를 예측하는 기준이 되지 않습니다.
  • 투자 결정은 과거 데이터에만 의존하지 않고 여러 정보와 전략을 고려해야 합니다.
    제공된 정보를 근거로 투자 결정을 내리는 것은 전적으로 투자자의 책임입니다.

 

볼린저밴드 트레이드-Ver01 전략(Bollinger Bands & True Range (TR) 기반 매수/매도 전략)

 

1. 전략 개요

주식 데이터의 Bollinger Bands, True Range(TR) 및 MA100 기울기를 사용하여 매수와 매도 시점을 결정합니다.



2. 기본 로직

  • 전략에 사용하는 값
    • 중간 밴드 (Middle Band): 주가의 20일 이동평균선 계산
    • 상단 밴드 (Upper Band): 중간 밴드 + (20일 주가의 표준편차 x 2)
    • 하단 밴드 (Lower Band): 중간 밴드 - (20일 주가의 표준편차 x 2)
    • True Range (TR): max(오늘의 고가 - 오늘의 저가, 오늘의 고가 - 어제의 종가, 어제의 종가 - 오늘의 저가)의 평균값
    • MA100 Gradient: 100일 이동평균선의 기울기. 이 기울기는 가격 추세의 방향성을 나타낼 수 있습니다.
  • 매수/매도 전략:
    • 매수 조건:
      • 현재 주가가 하단 밴드보다 낮으면 매수를 고려합니다.
      • 이후, 주가가 다시 하단 밴드 위로 올라갈 때 실제 매수 결정을 합니다.
      • 추가적으로, MA100의 기울기가 양수(즉, 긍정적인 추세)일 경우에만 매수를 진행합니다.
    • 매도 조건:
      • 현재 주가가 상단 밴드보다 높으면 매도를 고려합니다.
      • 이후, 주가가 다시 상단 밴드 아래로 내려갈 때 실제 매도 결정을 합니다.
    • 손절 조건:
      • True Range (TR) 값을 사용하여 손절 기준을 정합니다.
      • 만약 매수 포지션이 활성화된 상태에서 주가가 매수 가격에서 TR의 일정 배수만큼 떨어지면 해당 포지션을 매도(손절)합니다.

 

 

위 트레이딩 전략을 이용한, 삼성전자의 2015년부터 2023년 현재(8월14일)까지의 차트를 그려보면 다음과 같습니다.

평균 수익은 10.48%이고, 총 11번의 트레이딩이 있어고 그 중에 4번만 수익을 봤네요.

 

 

 

Kodex 200에 같은 로직을 사용해보면 아래와 같습니다. 2015년부터 2023년 8월까지, 총 10번의 트레이드가 있었고 3번이 수익이 났네요.

 

ATR(Average True Range)을 이용한 손절(Stop Loss) 설정

True Range (변동성)는 주가의 가격 변동을 나타내는 지표입니다. 터틀 트레이딩에서는 최근 N일간의 True Range 평균 값을 사용하여 스톱 로스(손절선)를 설정합니다. (이 방법은 투자보다는 트레이딩에 적합한 손절선 계산 방법입니다.)

 

True Range의 계산 로직은 아래와 같습니다.

  • True Range = max(High - Low, abs(High - Previous Close), abs(Low - Previous Close))

 

위 공식을 풀어보면, 아래 3개 중에 가장 큰 값이 True Range가 됩니다.

  • 오늘고가 - 오늘저가
  • 절댓값(오늘고가 - 전일종가)
  • 절댓값(오늘저가 - 전일종가)

 

실제 삼성전자의 주가를 이용하여 TR(True Range)를 구해보면 아래 엑셀표와 같습니다. 삼성전자의 2023년 8월 10일 TR은 1,100원입니다. 그리고 2023년 8월 10일 ATR(20)은 TR의 최근 20일 평균이므로 1,475원입니다.

 

ATR(20) 값인 1475원을 사용하여 손절선을 설정합니다. 터틀 트레이딩에서는 ATR(20)의 2배를 사용한다고 합니다. 손절금액을 더 크게 설정하려면 배수를 높이면 됩니다. ATR(20)을 이용해 아래와 같이 손절률을 계산할 수 있습니다.(2배 사용)

  • 손절률 = (현재가 - (현재가 - (ATR20 * 2))) / 현재가 * 100

 

삼성전자의 2023년 8월 10일 종가(현재가)가 68,000이므로 위 공식에 대입해 보면 아래와 같이 손절률이 나옵니다.

  • (68000 - (68000 - (1475*2)))/68000 * 100 = 4.33%

 

다음 단계가 매우 중요합니다. 손절률인 4.33%를 사용하여 매수할 수량(금액)을 결정해야 합니다. 먼저 감내 가능한 손실 금액을 결정해야 합니다. 즉, 얼마까지 손실이 허용되는지, 얼마까지 손실이 발생하면 반드시 손절할 것인지를 결정해야 합니다. 감내 가능한 손절 금액은 개인마다 다릅니다. 예를 들어, 한 번의 거래에서 최대 50,000원까지 손실을 감수할 수 있다면, 아래 공식을 사용해 매수 가능한 수량을 계산할 수 있습니다.

  • 매수수량 = 손실가능금액 / (ATR20 * 2)

 

위 공식을 사용해, 삼성전자의 23년 8월 10일 기준으로 손실이 50,000원까지 나도 된다고 가정하면, 아래와 같이 매수 수량을 구할 수 있습니다.

  • 50000 / (1475 * 2) = 17

 

삼성전자의 2023년 8월 10일 종가가 68,000원입니다. 68,000원으로 17주를 사면 총 1,156,000 원이 필요합니다.

삼성전자 17주를 산 후에 -4.33%로 Stop-Loss를 설정합니다. 그러면, 약 50,000원 정도 손실이 되면 자동 손절이 이루어지게 됩니다.

 

이상, ATR을 사용해 손절을 잡는 방법이었습니다.

기회가 된다면 터틀 트레이딩이란 책을 읽어보시기 바랍니다.

트레이드 전략 - 위꼬리가 긴 하루 #4


'트레이드 전략 - 위꼬리가 긴 하루'의 마지막 글입니다.
제목에 비해 별 내용이 없는데라고 생각하실 분들도 있을듯 싶네요.
다양한 방법의 하나로 봐주시면 감사하겠습니다.

앞에서 2020년 10월 한달 데이터에 대해서 위꼬리 전략을 적용했을때, TE(Trading Edge)를 구해보니 좋지 않았습니다.
여기서는 기간 조건을 제거하고 모든 데이터에 대해 위꼬리 전략을 적용해봅니다.
간단합니다. 앞의 글의 SQL에서 일자 조건만 제거하면 됩니다. (불행히도, 현재 사용하는 데이터에는 2019년 부터 2021년까지의 데이터만 존재합니다.)
아래와 같이 SQL을 작성하고 실행해봅니다.

WITH R01 AS(
    SELECT T2.STK_CD ,T2.DT BUY_DT ,T2.C_PRC BUY_PRC ,T2.H_L ,T2.UP_TAIL ,T2.H_L_CHG ,T2.UP_TAIL_RT
           ,T3.DT SELL_DT ,T3.C_PRC SELL_PRC
           ,ROUND((T3.C_PRC - T2.C_PRC) / T2.C_PRC * 100,2) PROF_RT # 3일후 매도시 수익률
    FROM   (
            SELECT T1.STK_CD
                   ,T1.DT
                   ,T1.C_PRC
                   ,T1.H_PRC - T1.L_PRC H_L # 고가-저가 길이
                   ,T1.H_PRC - GREATEST(T1.C_PRC,T1.O_PRC) UP_TAIL # 위꼬리 길이
                   ,ROUND((T1.H_PRC - T1.L_PRC) / T1.L_PRC * 100,2) H_L_CHG # 위꼬리 등락률
                   ,ROUND((T1.H_PRC - GREATEST(T1.C_PRC,T1.O_PRC))
                                  / (T1.H_PRC - T1.L_PRC) * 100,2) UP_TAIL_RT # 위꼬리 비율
                   ,T1.STK_DT_NO
            FROM   MYSTKDB.HISTORY_DT T1
            WHERE  1=1
            # AND    T1.DT >= STR_TO_DATE('20201001','%Y%m%d') # 일자 조건 제거
            # AND    T1.DT <  STR_TO_DATE('20201101','%Y%m%d') # 일자 조건 제거
            ) T2
            INNER JOIN MYSTKDB.HISTORY_DT T3 # 위꼬리 발생 3일 후 주가 데이터를 조인
               ON (T3.STK_CD = T2.STK_CD AND T3.STK_DT_NO = T2.STK_DT_NO + 3)
    WHERE   T2.H_L_CHG >= 10 # 고가-저가 등락률이 10% 이상
    AND     T2.UP_TAIL_RT >= 90 # 위꼬리 비율이 90% 이상
    ORDER BY PROF_RT DESC
    )
SELECT  T2.*
        ,ROUND((T2.W_PROF_RT * T2.W_RT) - (ABS(T2.L_PROF_RT)* T2.L_RT),2) TE
FROM    (
		SELECT  DATE_FORMAT(T1.BUY_DT, '%Y') YY # --> 년별
		        ,COUNT(*) TRD_CNT
				,SUM(CASE WHEN T1.PROF_RT >= 1 THEN 1 END) W_CNT
				,ROUND(AVG(CASE WHEN T1.PROF_RT >= 1 THEN T1.PROF_RT END),2) W_PROF_RT
				,ROUND(SUM(CASE WHEN T1.PROF_RT >= 1 THEN 1 END) / COUNT(*) * 100, 2) W_RT
				,SUM(CASE WHEN T1.PROF_RT < 1 THEN 1 END) L_CNT
				,ROUND(AVG(CASE WHEN T1.PROF_RT < 1 THEN T1.PROF_RT END),2) L_PROF_RT
				,ROUND(SUM(CASE WHEN T1.PROF_RT < 1 THEN 1 END) / COUNT(*) * 100, 2) L_RT
		FROM    R01 T1
		GROUP BY DATE_FORMAT(T1.BUY_DT, '%Y') # --> 년별
		) T2
ORDER BY T2.YY ASC
;

YY     TRD_CNT   W_CNT   W_PROF_RT   W_RT    L_CNT   L_PROF_RT   L_RT    TE       
------ --------- ------- ----------- ------- ------- ----------- ------- -------- 
2019   333       176     8.68        52.85   157     -3.67       47.15   285.70   
2020   382       166     8.90        43.46   216     -6.75       56.54   5.15     
2021   291       132     8.16        45.36   159     -5.60       54.64   64.15


결과를 보기 좋게, 년별로 집계헀습니다.
결과를 보면, 2019년에는 TE가 매우 높았으나, 2020년에는 다소 낮은 것을 알 수 있습니다.
비록 3년간의 데이터지만, 년별로 TE를 보면 마이너스가 아니기 때문에, 해당 전략은 좀 더 다듬고 연구해 볼 필요가 있지 않나 생각이 듭니다.
아래와 같은 내용을 추가로 고려해 볼 필요가 있습니다.

  • 종목의 주가(저가주를 제외할까? 저가주만 노릴까?)
  • 거래량(거래량이 폭발적이었는가)
  • 추세(이평선이 상승 추세인가?)
  • 시장의 추세(지수가 상승 중인가?)
  • 손절과 익절
  • 보유 기간을 늘리면? 줄이면?
  • 위꼬리의 비율을 조절한다면?


위와 같은 내용을 추가하는 과정에서 너무 과최적화가 되지 않도록 주의가 필요합니다.
조건이 많아질수록 이도 저도 아닌 결과가 나오는 경우가 많드라고요.
적절하게 조건을 추가해서 더 좋은 TE가 만들어지도록 노력을 해보고, 가능성이 있다면, 파이썬으로 정밀하게 트레이딩을 시뮬레이션 해봐야겠죠.
그리고, TE가 높다고 해서 항상 수익이 아니죠. 마이너스. 구간이 언제나 존재합니다. 그러한 구간에 대한 대응 전략과, 생존 전략이 없다면 트레이드는 금기가 아닐까 싶습니다.

준비한 글은 여기까지입니다. 마지막으로 한 번더!^^;;;
절대 주식 투자나 종목 매매를 권장하는 글이 아닙니다. 기술적인 설명을 위한 글이며, 이 글을 참고해 발생한 투자 손실에는 그 누구도 절대 책임지지 않습니다.

감사합니다.

트레이드 전략 - 위꼬리가 긴 하루 #3

위꼬리가 긴 하루, 세 번째입니다.

이번에는 앞에서 구한 2020년 10월의 트레이드 데이터를 집계처리합니다.
데이터 집계를 통해, 승리할 확률과, 승리했을때의 수익률을 구할 수 있습니다. 반대로 패배의 확률도 알 수 있죠. 데이터 집계를 통해 TE(Trading Edge)를 구할 수 있으며, 이를 통해 과연 사용할 만한 전략인지 고민해볼 수 있습니다.

설명에 앞서.. 또 한 번 거듭 말씀드립니다.
여기서 소개하는 트레이드 전략은 매우 위험하며, 절대 주식 투자나 종목 매매를 권장하는 글이 아닙니다. 기술적인 설명을 위한 글이며, 이 글을 참고해 발생한 투자 손실에는 그 누구도 절대 책임지지 않습니다.

먼저 승리와 패배를 정의해야 합니다. 아래와 같이 정의합니다.

  • 승리: 매도시 1% 이상 수익
  • 패배: 매도시 1% 미만 수익 또는 손실


아래와 같이 SQL을 구현합니다. 앞에 글에서 사용한 SQL을 그대로, WITH R01 AS로 묶은 다음에,
R01에 대해 집계처리하면 됩니다. 집계 처리 과정에서 CASE를 사용해 승리와 패배를 구분합니다.

WITH R01 AS(
    SELECT T2.STK_CD ,T2.DT BUY_DT ,T2.C_PRC BUY_PRC ,T2.H_L ,T2.UP_TAIL ,T2.H_L_CHG ,T2.UP_TAIL_RT
           ,T3.DT SELL_DT ,T3.C_PRC SELL_PRC
           ,ROUND((T3.C_PRC - T2.C_PRC) / T2.C_PRC * 100,2) PROF_RT # 3일후 매도시 수익률
    FROM   (
            SELECT T1.STK_CD
                   ,T1.DT
                   ,T1.C_PRC
                   ,T1.H_PRC - T1.L_PRC H_L # 고가-저가 길이
                   ,T1.H_PRC - GREATEST(T1.C_PRC,T1.O_PRC) UP_TAIL # 위꼬리 길이
                   ,ROUND((T1.H_PRC - T1.L_PRC) / T1.L_PRC * 100,2) H_L_CHG # 위꼬리 등락률
                   ,ROUND((T1.H_PRC - GREATEST(T1.C_PRC,T1.O_PRC))
                                  / (T1.H_PRC - T1.L_PRC) * 100,2) UP_TAIL_RT # 위꼬리 비율
                   ,T1.STK_DT_NO # --> 종목별일자 순번
            FROM   MYSTKDB.HISTORY_DT T1
            WHERE  1=1
            AND    T1.DT >= STR_TO_DATE('20201001','%Y%m%d')
            AND    T1.DT <  STR_TO_DATE('20201101','%Y%m%d')
            ) T2
            INNER JOIN MYSTKDB.HISTORY_DT T3 # 위꼬리 발생 3일 후 주가 데이터를 조인
               ON (T3.STK_CD = T2.STK_CD AND T3.STK_DT_NO = T2.STK_DT_NO + 3)
    WHERE   T2.H_L_CHG >= 10 # 고가-저가 등락률이 10% 이상
    AND     T2.UP_TAIL_RT >= 90 # 위꼬리 비율이 90% 이상
    ORDER BY PROF_RT DESC
    )
SELECT  COUNT(*) TRD_CNT
        ,SUM(CASE WHEN T1.PROF_RT >= 1 THEN 1 END) W_CNT
        ,ROUND(AVG(CASE WHEN T1.PROF_RT >= 1 THEN T1.PROF_RT END),2) W_PROF_RT
        ,ROUND(SUM(CASE WHEN T1.PROF_RT >= 1 THEN 1 END) / COUNT(*) * 100, 2) W_RT
        ,SUM(CASE WHEN T1.PROF_RT < 1 THEN 1 END) L_CNT
        ,ROUND(AVG(CASE WHEN T1.PROF_RT < 1 THEN T1.PROF_RT END),2) L_PROF_RT
        ,ROUND(SUM(CASE WHEN T1.PROF_RT < 1 THEN 1 END) / COUNT(*) * 100, 2) L_RT
FROM    R01 T1
;

TRD_CNT   W_CNT   W_PROF_RT   W_RT    L_CNT   L_PROF_RT   L_RT    
--------- ------- ----------- ------- ------- ----------- ------- 
28        10      7.17        35.71   18      -4.91       64.29


위 SQL을 통해 얻은 결과의 정보를 정리해보면 아래와 같습니다.

  • TRD_CNT: 매매 횟수
  • W_CNT: 승리 횟수
  • W_PROF_RT: 승리시 평균 수익률
  • W_RT: 승률
  • L_CNT: 패패 횟수
  • L_PROF_RT: 패배시 평균 수익률
  • L_RT: 패율

위 결과를 통해, 승리시 평균적으로 7.17%의 수익이 났으며, 승률이 35.71%인 것을 알 수 있습니다.
반대로 패배시 평균 수익은 -4.91%이며, 패배할 확률이 64.29%나 됩니다.
이 내용을 가지고 '터틀 트레이딩'에서 설명하는 TE(Trading Edge)를 구해보면 아래와 같습니다.

  • TE = (승리시 평균수익 * 승률) - (절댓값(패배시 평균 수익) * 패율)
  • TE = (7.17 * 35.71) - (ABS(4.91) * 64.29) = -59.62


TE가 마이너스(-59.62)라는 것은 트레이드를 할 수록 손해볼 확률이 높다는 뜻입니다.
하지만, 저희는 단지 2020년 10월에 대해서만 TE를 산출했습니다.
그러므로 가능한 많은 데이터에 위꼬리 전략을 적용해 TE를 구해볼 필요가 있습니다.
이와 관련해서는 다음 글에서 살펴보도록 하겠습니다.

끝으로, TE까지 구하는 SQL을 만들어보면 아래와 같습니다. 기존의 집계한 데이터를 한 단계 밑으로 인라인 뷰 처리한 후에 TE 고식을 적용합니다.

WITH R01 AS(
    SELECT T2.STK_CD ,T2.DT BUY_DT ,T2.C_PRC BUY_PRC ,T2.H_L ,T2.UP_TAIL ,T2.H_L_CHG ,T2.UP_TAIL_RT
           ,T3.DT SELL_DT ,T3.C_PRC SELL_PRC
           ,ROUND((T3.C_PRC - T2.C_PRC) / T2.C_PRC * 100,2) PROF_RT # 3일후 매도시 수익률
    FROM   (
            SELECT T1.STK_CD
                   ,T1.DT
                   ,T1.C_PRC
                   ,T1.H_PRC - T1.L_PRC H_L # 고가-저가 길이
                   ,T1.H_PRC - GREATEST(T1.C_PRC,T1.O_PRC) UP_TAIL # 위꼬리 길이
                   ,ROUND((T1.H_PRC - T1.L_PRC) / T1.L_PRC * 100,2) H_L_CHG # 위꼬리 등락률
                   ,ROUND((T1.H_PRC - GREATEST(T1.C_PRC,T1.O_PRC))
                                  / (T1.H_PRC - T1.L_PRC) * 100,2) UP_TAIL_RT # 위꼬리 비율
                   ,T1.STK_DT_NO # --> 종목별일자 순번
            FROM   MYSTKDB.HISTORY_DT T1
            WHERE  1=1
            AND    T1.DT >= STR_TO_DATE('20201001','%Y%m%d')
            AND    T1.DT <  STR_TO_DATE('20201101','%Y%m%d')
            ) T2
            INNER JOIN MYSTKDB.HISTORY_DT T3 # 위꼬리 발생 3일 후 주가 데이터를 조인
               ON (T3.STK_CD = T2.STK_CD AND T3.STK_DT_NO = T2.STK_DT_NO + 3)
    WHERE   T2.H_L_CHG >= 10 # 고가-저가 등락률이 10% 이상
    AND     T2.UP_TAIL_RT >= 90 # 위꼬리 비율이 90% 이상
    ORDER BY PROF_RT DESC
    )
SELECT  T2.*
        ,ROUND((T2.W_PROF_RT * T2.W_RT) - (ABS(T2.L_PROF_RT)* T2.L_RT),2) TE
FROM    (
		SELECT  COUNT(*) TRD_CNT
				,SUM(CASE WHEN T1.PROF_RT >= 1 THEN 1 END) W_CNT
				,ROUND(AVG(CASE WHEN T1.PROF_RT >= 1 THEN T1.PROF_RT END),2) W_PROF_RT
				,ROUND(SUM(CASE WHEN T1.PROF_RT >= 1 THEN 1 END) / COUNT(*) * 100, 2) W_RT
				,SUM(CASE WHEN T1.PROF_RT < 1 THEN 1 END) L_CNT
				,ROUND(AVG(CASE WHEN T1.PROF_RT < 1 THEN T1.PROF_RT END),2) L_PROF_RT
				,ROUND(SUM(CASE WHEN T1.PROF_RT < 1 THEN 1 END) / COUNT(*) * 100, 2) L_RT
		FROM    R01 T1
		) T2
;

TRD_CNT   W_CNT   W_PROF_RT   W_RT    L_CNT   L_PROF_RT   L_RT    TE       
--------- ------- ----------- ------- ------- ----------- ------- -------- 
28        10      7.17        35.71   18      -4.91       64.29   -59.62


감사합니다.

트레이드 전략 - 위꼬리가 긴 하루 #2

지난 글에 이어서 '위꼬리가 긴 하루'를 계속해서 분석해보겠습니다.

https://sweetquant.tistory.com/374

트레이드 전략 - 위꼬리가 긴 하루 #1

트레이드 전략 - 위꼬리가 긴 하루 #1 최근 매매에 들어간 종목 세 개 정도가 계속해서 위꼬리가 나오네요. 결과적으로는 매우 않좋게 마무리가 되었습니다. ㅠㅠ. 세 종목이 다.!!!! 그래서, '위꼬

sweetquant.tistory.com


지난 글에서는 2020년 10월 중에 위꼬리가 긴 데이터를 검색했습니다. 이번에는 위꼬리가 긴 종목을 매도했을 때에 수익률이 어떤지까지 연결해보려고 합니다.
매매를 하기 위해서는 매수(Buy) 시점, 매도(Sell) 시점을 정해야 합니다. 매수 시점은 앞에 글에서 구한 위꼬리가 나온 날의 종가입니다. 매도 시점은 간단하게 3일 후 종가로 하도록 하겠습니다.
지난 글의 SQL에 아래와 같이 3일 후 종가를 가져오도록 처리하면 됩니다. SQL이 좀 길어졌지만 겁먹지 말고 천천히 따라서 입력해보시기 바랍니다.

SELECT  T2.STK_CD ,T2.DT BUY_DT ,T2.C_PRC BUY_PRC ,T2.H_L ,T2.UP_TAIL ,T2.H_L_CHG ,T2.UP_TAIL_RT
        ,T3.DT SELL_DT ,T3.C_PRC SELL_PRC
        ,ROUND((T3.C_PRC - T2.C_PRC) / T2.C_PRC * 100,2) PROF_RT # 3일후 매도시 수익률
FROM    (
        SELECT  T1.STK_CD
                ,T1.DT
                ,T1.C_PRC
                ,T1.H_PRC - T1.L_PRC H_L # 고가-저가 길이
                ,T1.H_PRC - GREATEST(T1.C_PRC,T1.O_PRC) UP_TAIL # 위꼬리 길이
                ,ROUND((T1.H_PRC - T1.L_PRC) / T1.L_PRC * 100,2) H_L_CHG # 위꼬리 등락률
                ,ROUND((T1.H_PRC - GREATEST(T1.C_PRC,T1.O_PRC))
                   / (T1.H_PRC - T1.L_PRC) * 100,2) UP_TAIL_RT # 위꼬리 비율
                ,T1.STK_DT_NO # --> 종목별일자 순번
        FROM    MYSTKDB.HISTORY_DT T1
        WHERE   1=1
        AND     T1.DT >= STR_TO_DATE('20201001','%Y%m%d')
        AND     T1.DT <  STR_TO_DATE('20201101','%Y%m%d')
        ) T2 INNER JOIN MYSTKDB.HISTORY_DT T3 # 위꼬리 발생 3일 후 주가 데이터를 조인
             ON (T3.STK_CD = T2.STK_CD AND T3.STK_DT_NO = T2.STK_DT_NO + 3)
WHERE   T2.H_L_CHG >= 10 # 고가-저가 등락률이 10% 이상
AND     T2.UP_TAIL_RT >= 90 # 위꼬리 비율이 90% 이상
ORDER BY PROF_RT DESC
;


여기서 포인트는 바로 STK_DT_NO입니다. 해당 컬럼은 종목별 일자별 순번이 저장된 컬럼입니다. 해당 컬럼을 이용하면 해당 종목의 3일후 데이터를 가져올 수 있습니다. 날짜 계산을 통해서도 처리할 수 있겠지만 휴일 처리가 매우 복잡해집니다. 그러므로 이와 같은 종목별 순번을 사용하면 손쉽게 몇일 후, 몇일 전 데이터를 조인으로 처리할 수 있습니다(이와 같은 방법을 이미 아시는 분들도 있겠지만, 솔직히 소문내지 않고 저만 알고 싶은 방법입니다.)
위 SQL의 결과를 살펴보면 아래와 같습니다.

STK_CD   BUY_DT       BUY_PRC     H_L         UP_TAIL     H_L_CHG   UP_TAIL_RT   SELL_DT      SELL_PRC    PROF_RT   
-------- ------------ ----------- ----------- ----------- --------- ------------ ------------ ----------- --------- 
013700   2020-10-27   1910.000    275.000     255.000     14.55     92.73        2020-10-30   2415.000    26.44     
052900   2020-10-20   1850.000    410.000     380.000     22.53     92.68        2020-10-23   2015.000    8.92      
025880   2020-10-30   2095.000    255.000     245.000     12.23     96.08        2020-11-04   2230.000    6.44      
... 생략 ... 
033660   2020-10-23   13450.000   1350.000    1250.000    10.07     92.59        2020-10-28   12200.000   -9.29     
090710   2020-10-30   1430.000    240.000     230.000     16.90     95.83        2020-11-04   1285.000    -10.14    
289080   2020-10-14   7120.000    710.000     660.000     10.04     92.96        2020-10-19   6040.000    -15.17

가장 위에 있는 '013700' 종목은 3일 후 수익률이 무려 26.44 %입니다. 행복한 결말이죠. 하지마 가장 아래에 있는 '289080'은 3일 후에 무려 15.17%를 손해봅니다. 불행한 결말이죠. 이처럼 주식 트레이딩에는 행복과 불행이 항상 공존합니다. 행복만 바라보고 트레이드를 한다면 불행의 쓰디쓴 맛을 보게 됩니다.
실제로도 그런지 차트를 통해 확인해보도록 하겠습니다. 이처럼 데이터 분석과 전략 생성을 위해서는 중간 중간 데이터 확인을 해야 합니다.
먼저 013700의 차트를 살펴보면 아래와 같습니다. 3일후 주가가 오른 것을 알 수 있습니다.


이번에는 289080의 차트를 살펴봅니다. 3일후 주가가 떨어진것을 알 수 있습니다.


오늘은 위꼬리가 발생한 종목의 3일후 주가를 연결하고 수익률까지 구해봤습니다. 다음 글에서는 데이터 집계를 통해 트레이딩 엣지(Trading Edge, TE)를 구해보도록 하겠습니다.
다시 한 번 말씀드리지만,
소개하는 트레이드 전략은 매우 위험합니다. 주식 차트의 봉 모양을 보고 매매를 한다는 것 자체가 매우 위험한 방법입니다. 절대 주식 투자나 종목 매매를 권장하는 글이 아닙니다. 기술적인 설명을 위한 글이며, 이 글을 참고해 발생한 투자 손실에는 그 누구도 절대 책임지지 않습니다.

감사합니다.


트레이드 전략 - 위꼬리가 긴 하루 #1

최근 매매에 들어간 종목 세 개 정도가 계속해서 위꼬리가 나오네요.
결과적으로는 매우 않좋게 마무리가 되었습니다. ㅠㅠ. 세 종목이 다.!!!!
그래서, '위꼬리'를 신호로 삼아 매매를 하면 어떻게 될까를 분석해볼까 합니다.
더불어, 저의 경우에는 트레이드 전략을 어떻게 만들고 있는지도 간단히 참고하실 수 있을거 같습니다.

우선 여기서 소개하는 트레이드 전략은 매우 위험합니다. 주식 차트의 봉 모양을 보고 매매를 한다는 것 자체가 매우 위험한 방법입니다.
본격적인 설명에 앞서, 절대 주식 투자나 종목 매매를 권장하는 글이 아닙니다. 기술적인 설명을 위한 글이며, 이 글을 참고해 발생한 투자 손실에는 그 누구도 절대 책임지지 않습니다.

여기서 사용한 테스트 데이터는 '평생 필요한 데이터 분석'의 주식 데이터입니다. 아래에서 다운로드 할 수 있습니다.
- https://blog.naver.com/ryu1hwan/222664620661

해당 DB에는 2019년부터 2021년말까지의 일별 주가 데이터가 존재합니다. 또한 일부 종목은 없을수도 있지만, 대부분의 종목은 있다고 보시면 됩니다.

먼저 '위꼬리 긴 하루'를 아래와 같이 정의합니다. (아래 내용은 각자 자유롭게 기준을 만들수 있겠죠.)

  • 고가-저가 등락률이 10% 이상이면서, 위꼬리 길이가 고가-저가 길이의 90% 이상을 차지할 것
  • 고가-저가 길이(H_L): 고가 - 저가
  • 위꼬리 길이(UP_TAIL): 고가 - GREATEST(종가,시가)
  • 고가-저가 등락률(H_L_CHG): (고가 - 저가) / 저가 * 100
  • 위꼬리 길이 비율(UP_TAIL_RT): 위꼬리 길이 / 고가-저가 길이 * 100

2020년 10월 주가 데이터 중에서 위 조건에 맞는 데이터를 조회해봅니다. 아래와 같습니다.

SELECT T2.*
FROM   (
       SELECT  T1.STK_CD
               ,T1.DT
               ,T1.C_PRC
               ,T1.H_PRC - T1.L_PRC H_L # 고가-저가 길이
               ,T1.H_PRC - GREATEST(T1.C_PRC,T1.O_PRC) UP_TAIL # 위꼬리 길이
               ,ROUND((T1.H_PRC - T1.L_PRC) / T1.L_PRC * 100,2) H_L_CHG # 위꼬리 등락률
               ,ROUND((T1.H_PRC - GREATEST(T1.C_PRC,T1.O_PRC))
                    / (T1.H_PRC - T1.L_PRC) * 100,2) UP_TAIL_RT # 위꼬리 비율
        FROM   MYSTKDB.HISTORY_DT T1
        WHERE  1=1
        AND    T1.DT >= STR_TO_DATE('20201001','%Y%m%d')
        AND    T1.DT <  STR_TO_DATE('20201101','%Y%m%d')
        ) T2
WHERE   T2.H_L_CHG >= 10 # 고가-저가 등락률이 10% 이상
AND     T2.UP_TAIL_RT >= 90 # 위꼬리 비율이 90% 이상
;

STK_CD   DT           C_PRC       H_L         UP_TAIL     H_L_CHG   UP_TAIL_RT   
-------- ------------ ----------- ----------- ----------- --------- ------------ 
001840   2020-10-06   5540.000    570.000     540.000     10.34     94.74        
054450   2020-10-08   15450.000   2450.000    2250.000    16.07     91.84        
007210   2020-10-12   2010.000    205.000     190.000     10.28     92.68    
... 생략



가장 위에 있는 '001840'이란 종목이 2020년 10월 6일에 위꼬리가 만들어진 것으로 나왔습니다. 실제 그랬는지 차트를 통해 살펴봐야겠죠. 차트를 확인해 보니, 아래와 같이 10월 6일에 위꼬리가 긴 음봉이 만들어졌네요. 그 후, 4일 후 정도까지는 약간 올랐지만 쭉 하락세네요.




결과의 두 번째인 '054450'도 살펴보죠. 10월 8일에 위꼬리가 긴 양봉이 만들어 졌네요. 마찬가지로 잠깐 올랐다가 쭈욱 하락세네요.



이처럼 SQL만 이용해서, 특정 패턴의 차트를 찾아낼 수 있습니다. 오늘은 여기까지 살펴보고, 다음 글에 이어서 계속 설명하도록 하겠습니다. 감사합니다.

오늘은 가져온 파이썬의 pykrx를 사용해 주가 이력 정보를 가져오고,

pymysql을 사용해, 가져온 주가 정보를 개인용 주식 DB에 insert까지 해보도록 하겠습니다.

 

 

먼저 아래를 참고해 테이블을 생성합니다.

CREATE TABLE MYTRDDB.KRX_HIST_DT(
   STK_CD VARCHAR(40) NOT NULL
   ,DT DATE NOT NULL
   ,O_PRC DECIMAL(18,3)
   ,H_PRC DECIMAL(18,3)
   ,L_PRC DECIMAL(18,3)
   ,C_PRC DECIMAL(18,3)
   ,VOL DECIMAL(18,3)
   ,CHG_RT DECIMAL(18,3)
   ,PRIMARY KEY(STK_CD, DT)
);

 

간단히 dataframe 관련된 명령어 몇 개를 살펴봅니다.

# Dataframe의 Index 값 중에, 최대값, 최소값 가져오기.
df.index.min()
df.index.max()

# Dataframe의 Index 값을 loop로 순차적으로 가져오기.
# 가저온 Index 값을 이해용해 해당 로우의 데이터를 가져오기.
for ix in df.index:
    print(ix)
    print(df.loc[ix].시가)
    print(df.loc[ix].고가)

 

최종 아래와 같은 소스코드를 통해 삼성전자(005930)의 주가 정보를 가져와, 우리가 위에서 만들었던 MYSTKDB.KRX_HIST_DT에 입력할 수 있습니다.

기존에 클래스내에 static으로 만들었던 함수는, static을 모두  제거했습니다.

get_stock_history에서 새로 만든 함수인, insert_hist_dt를 호출하도록 구성되어 있습니다.

get_stock_history에서는 pykrx를 통해, 데이터프레임에 주가 정보를 입력하고,

insert_hist_dt에서는 데이터프레임을 넘겨받아 주가 데이터를 insert합니다.

이때, 기존에 입력된 구간과 겹쳐지지 않도록 delete를 처리합니다.

import pymysql
from pykrx import stock
from datetime import datetime, timedelta


class MyCollectKRX:
    def get_stock_master(self, _market):
        stk_master = []
        for stk_cd in stock.get_market_ticker_list(market=_market):
            stk_nm = stock.get_market_ticker_name(stk_cd)
            stk_master.append((stk_cd, stk_nm, _market))
        return stk_master

    def get_stock_history(self, _stk_cd, _fr_ymd, _to_ymd):
        if _to_ymd == '':
            _to_ymd = datetime.now().strftime('%Y%m%d')
        if _fr_ymd == '':
            _fr_ymd = (datetime.strptime(_to_ymd, '%Y%m%d') - timedelta(weeks=54)).strftime('%Y%m%d')

        df = stock.get_market_ohlcv(_fr_ymd, _to_ymd, _stk_cd)

        self.insert_hist_dt(_stk_cd, df)

    def insert_hist_dt(self, _stk_cd, _df):
        # MySQL 연결 객체 생성
        myConn = pymysql.connect(user='???', password='???', host='localhost', port=3306,
                                 charset='utf8', database='MYTRDDB')
        myCursor = myConn.cursor()
        _fr_ymd = _df.index.min()
        _to_ymd = _df.index.max()
        sql_del = "DELETE T1 FROM MYTRDDB.KRX_HIST_DT T1 WHERE T1.STK_CD = %s AND T1.DT BETWEEN %s AND %s"
        myCursor.execute(sql_del, (_stk_cd, _fr_ymd, _to_ymd))

        for ix in _df.index:
            sql_ins = "INSERT INTO MYTRDDB.KRX_HIST_DT(STK_CD ,DT ,O_PRC ,H_PRC ,L_PRC ,C_PRC ,VOL ,CHG_RT)"
            sql_ins = sql_ins + "               VALUES(%s     ,%s ,%s    ,%s    ,%s    ,%s    ,%s  ,%s)"
            myCursor.execute(sql_ins, (
            _stk_cd, ix, _df.loc[ix].시가, _df.loc[ix].고가, _df.loc[ix].저가, _df.loc[ix].종가, _df.loc[ix].거래량, _df.loc[ix].등락률))

        myConn.commit()
        myCursor.close()
        myConn.close()


if __name__ == '__main__':
    myCollectKRX = MyCollectKRX()
    stk_cd = '005930'
    myCollectKRX.get_stock_history(_stk_cd=stk_cd, _fr_ymd='', _to_ymd='')
    print('작업 완료')

 

현재 작성된 모듈은 mysql의 연결과 처리에 대한 모듈이 모두 포함되어  있습니다.

나중에 mysql 관련된 내용은 별도 클래스로 만들어 분리하는 것이 더욱 좋습니다.

오늘은 여기까지입니다.

PyKRX 를 이용해 주가 이력 정보를 가져오는 방법입니다.

 

이전 글에서는 PyKRX로 종목 마스터 정보를 가져왔습니다.(아래 링크 참고)

https://sweetquant.tistory.com/368

 

PyKRX - 주식 마스터 정보 가져오기

자신의 DB에 주식 마스터 테이블을 만들고, 파이썬에서 pykrx 모듈을 사용해 주식 마스터 정보를 가져오는 과정입니다. pykrx는 github에서 공개하고 있으며, 한국의 주식 정보를 쉽게 가져다 쓸수 있

sweetquant.tistory.com

 

 

아래와 같이 get_market_ohlcv(시작일, 종료일, 종목코드) 를 호출하면 Dataframe 형태로 주가 이력 정보를 가져옵니다.

조금더, 개발이 편하게 하기 위해서 별도의 get_stock_history라는 함수를 만들었습니다.

get_stock_history는 종목코드, 시작일, 종료일을 입력 받습니다. 만약에 시작일과 종료일이 비어 있으면, 이전 54주전부터 현재까지로 시작일과 종료일을 설정하도록 구성했습니다.

    def get_stock_history(_stk_cd, _fr_ymd, _to_ymd):
        if _to_ymd == '':
            _to_ymd = datetime.now().strftime('%Y%m%d')
        if _fr_ymd == '':
            _fr_ymd = (datetime.strptime(_to_ymd,'%Y%m%d') - timedelta(weeks=54)).strftime('%Y%m%d')

        df = stock.get_market_ohlcv(_fr_ymd, _to_ymd, _stk_cd)
        return df

 

날짜 관련 처리는 아래 글을 간단히 참고합니다.

https://sweetquant.tistory.com/371

 

Python 기초 - 날짜 다루기(문자에서 날짜로, 날짜에서 문자로, 날짜 계산)

Python 기초 - 날짜 다루기 간단한 날짜 다루는 방법입니다. datetime 라이브러리를 사용합니다. now: 현재 날짜, 시간을 가져옵니다. strftime: 날짜 데이터를 문자로 변형합니다. strpime: 문자 데이터를

sweetquant.tistory.com

 

get_stock_history 함수를 기존의 MyCollectKRX 클래스에 추가합니다. 아래와 같습니다.

from pykrx import stock
from datetime import datetime, timedelta

class MyCollectKRX:
    @staticmethod
    def get_stock_master(_market):
        stk_master = []
        for stk_cd in stock.get_market_ticker_list(market=_market):
            stk_nm = stock.get_market_ticker_name(stk_cd)
            stk_master.append((stk_cd, stk_nm, _market))
        return stk_master

    @staticmethod
    def get_stock_history(_stk_cd, _fr_ymd, _to_ymd):
        if _to_ymd == '':
            _to_ymd = datetime.now().strftime('%Y%m%d')
        if _fr_ymd == '':
            _fr_ymd = (datetime.strptime(_to_ymd,'%Y%m%d') - timedelta(weeks=54)).strftime('%Y%m%d')

        df = stock.get_market_ohlcv(_fr_ymd, _to_ymd, _stk_cd)
        return df


if __name__ == '__main__':
    myCollectKRX = MyCollectKRX()
    df = myCollectKRX.get_stock_history(_stk_cd='005930', _fr_ymd='', _to_ymd='')
	print(df)
    print('작업 완료')

 

위에서는 종목코드(_sstk_cd)에 005930을 넘겼습니다. 삼성전자입니다. 실행해보면, 아래와 같이 데이터프레임 형태의 결과를 얻을 수 있습니다.

 

날짜        시가    고가   저가    종가   거래량     거래대금    등락률                                              
2021-11-12  70200  70900  69900  70600  10087450  711487813500  1.00
2021-11-15  71700  71900  70900  71400  12420710  888880719596  1.13
2021-11-16  71500  72000  71300  71300  10919239  782118934000 -0.14

 

실행해보면 알겠지만, PyKRX에서 주가 이력을 가져오는 속도가 빠르지는 않습니다.

그러므로 자주 실행하면, PyKRX를 사용하는 다른 사람들에게 피해가 될 수 있으니,, 알아서 적당히 적절히 실행할 필요가 있습니다. 또한 한번 조회한 데이터는 개인 DB를 구축해서 관리할 필요가 있습니다. 관련해서는 다음에 글을 올려볼까 합니다.

 

Python 기초 - 날짜 다루기

 

간단한 날짜 다루는 방법입니다. datetime 라이브러리를 사용합니다.

 

now: 현재 날짜, 시간을 가져옵니다.

strftime: 날짜 데이터를 문자로 변형합니다.

strpime: 문자 데이터를 날짜로 변형합니다.

 

strftime과 strptime에서 사용하는 패턴은 아래와 같습니다(대소문자를 구분합니다.)

  • %Y: 네 자리 년도를 표시합니다.
  • %m: 두 자리 월을 표시합니다.
  • %d: 두 자리 일자를 표시합니다.
  • %H: 두 자리 시간, 24시간입니다.
  • %M: 두 자리 분(Minute)
  • %S: 두 자리 초(Sec)

 

timedelta: 시간을 더하거나 빼기 위해 사용합니다.

  • weeks나 days를 사용할 수 있습니다.

 

아래는 날짜를 처리하는 다양한 예제입니다.

from datetime import datetime, timedelta

print('')
print('-----------------------------------------------')
print('1. 현재 날짜와 시간을 출력합니다. 자료형(type)을 확인합니다.')
now_dt = datetime.now()
print(now_dt, type(now_dt))

print('')
print('-----------------------------------------------')
print('2. 현재 날짜와 시간을 문자로 변경(strftime)합니다. 자료형(type)을 확인합니다.')
str_now_dt = datetime.now().strftime('%Y%m%d %H:%M:%S')
print(str_now_dt, type(str_now_dt))

print('')
print('-----------------------------------------------')
print('3. 현재 날짜와 시간을 문자로 변경합니다. 시간은 제외합니다.')
str_now_d = datetime.now().strftime('%Y%m%d')
print(str_now_d, type(str_now_d))

print('')
print('-----------------------------------------------')
print('4. 현재에 3일전과 3일후를 계산(timedelta)합니다. 자료형(type)을 확인합니다.')
now_dt = datetime.now()
before_dt = now_dt - timedelta(days=3)
after_dt = now_dt + timedelta(days=3)
print('3일전:',before_dt)
print('지금:',now_dt)
print('3일후:',after_dt)

print('')
print('-----------------------------------------------')
print('5. 문자형 데이터를 날짜로 변경(strptime)합니다.')
now_d = '20221124'
now_dt = datetime.strptime(now_d,'%Y%m%d')
print(now_dt, type(now_dt))

 

Trade Optimizer


제가 구성한 Trade Optimizer의 구성에 대해 간단히 설명을 해볼까 합니다.
Trade Optimizer는 Python과 MySQL로 구성되어 있습니다.

  • Collector: 주식 관련 데이터를 수집합니다.
  • Trade Optimizer: 트레이딩을 위해 데이터를 정리 및 집계하고, 시뮬레이션을 수행합니다.
  • Telegram Bot: 만들어진, 시뮬레이션 결과를 텔레그램으로 전송합니다.

파이썬보다 SQL로 구성된 모듈이 더 많은 부분을 차지하고 있습니다.
파이썬이 종목별 상세한 시뮬레이션을 수행한다면,
SQL로는 전체 데이터를 집계하거나 큰 계산, 최종 트레이딩 대상 선정 등의 작업을 처리합니다.
저 같은 경우, SQL을 통해 전체적인 트레이딩 전략 방향을 잡고, 파이썬으로 상세한 시뮬레이션을 처리합니다.
개인적으로 파이썬만큼 SQL을 잘 다루는 능력이 중요하다고 생각합니다.

Trade Optimizer 모듈의 경우, 시총 Top-500 종목에 대해, 트레이딩 시뮬레이션(백테스트)을 수행하고,
오늘자로, 가장 트레이딩 EDGE가 있는 종목을 찾아내는 작업을 합니다.
저 같은 경우는 초단타가 아닌, 추세 추종으로 중장기 트레이딩을 하는 전략을 사용하고 있습니다.
중장기 트레이딩이다 보니, 실제 주식 매매는 손으로 직접 처리하고 있습니다.

감사합니다.

자신의 DB에 주식 마스터 테이블을 만들고, 파이썬에서 pykrx 모듈을 사용해 주식 마스터 정보를 가져오는 과정입니다.

 

pykrx는 github에서 공개하고 있으며, 한국의 주식 정보를 쉽게 가져다 쓸수 있도록 만들어진 모듈입니다.

아래 페이지를 통해 관련 정보 및, 사용 방법을 확인해주세요.

  - https://github.com/sharebook-kr/pykrx

 

GitHub - sharebook-kr/pykrx: KRX 주식 정보 스크래핑

KRX 주식 정보 스크래핑. Contribute to sharebook-kr/pykrx development by creating an account on GitHub.

github.com

 

개인적으로 pykrx를 만들어 배포해주신 분들께 매우 감사한 마음입니다. 많은 귀찮은 과정을 손쉽게 해결해주셨으니까요, 좋은일 가득하시길!!

 

아래 소스는 pykrx를 사용해, 종목코드와 종목명, 마켓명(코스피, 코스닥)을 리스트 형태로 가져와 조회하는 내용입니다.

앞으로의 확장성을 고려해 클래스 형태로 모듈을 만들었습니다.

# pip install pymysql
# pip install matplotlib
# pip install pykrx

from pykrx import stock


class MyCollectKRX:
    @staticmethod
    def get_stock_master(_market):
        stk_master = []
        for stk_cd in stock.get_market_ticker_list(market=_market):
            stk_nm = stock.get_market_ticker_name(stk_cd)
            stk_master.append((stk_cd, stk_nm, _market))
        return stk_master


if __name__ == '__main__':
    myCollectKRX = MyCollectKRX()
    stk_master_all = myCollectKRX.get_stock_master('KOSPI')
    stk_master_all.extend(myCollectKRX.get_stock_master('KOSDAQ')) # 리스트 두 개를 합치기 위해서는 extend 사용

    for stk in stk_master_all:
        print(stk)

 

 

위 모듈을 실행하면, 종목코드, 종목명, 마켓명을 리스트 형태로 출력할 수 있습니다. 이후, 이 데이터를 DB화해서 저장까지 해볼 수 있겠죠.

여기서, 눈여겨 볼만한거 하나는 리스트 형태의  데이터를 합치기 위해서는 extend를 사용한다는 점입니다.

append는 리스트 내에 하나의 요소를 더하는 작업이고, 리스트 두 개를 단순히 합치기 위해서는 extend를 사용해야 합니다.

 

위 내용을 DB로 저장하기 위해서 테이블을 생성할 차례입니다. 여기서는 MySQL을 사용합니다. 아래와 같이 MYTRDDB 데이터베이스를 생성하고, 해당 데이터베이스에 테이블까지 생성합니다.

# SQL 툴을 이용해 MySQL에 접속해서 실행
CREATE DATABASE MYTRDDB; # DB 생성

CREATE TABLE MYTRDDB.KRX_STOCK(
	STK_CD VARCHAR(40) NOT NULL
 	,STK_NM VARCHAR(200) NOT NULL
 	,MKT_NM VARCHAR(40) NOT NULL
	,PRIMARY KEY(STK_CD)
);

 

위 테이블에 Insert하는 과정까지 추가해서 파이썬 소스를 변경해보면, 아래와 같습니다.

# pip install pymysql
# pip install matplotlib
# pip install pykrx

from pykrx import stock
import pymysql  # MYSQL 연결및, SQL 실행을 위해 추가


class MyCollectKRX:
    @staticmethod
    def get_stock_master(_market):
        stk_master = []
        for stk_cd in stock.get_market_ticker_list(market=_market):
            stk_nm = stock.get_market_ticker_name(stk_cd)
            stk_master.append((stk_cd, stk_nm, _market))
        return stk_master


if __name__ == '__main__':
    myCollectKRX = MyCollectKRX()
    stk_master_all = myCollectKRX.get_stock_master('KOSPI')
    stk_master_all.extend(myCollectKRX.get_stock_master('KOSDAQ'))  # 리스트 두 개를 합치기 위해서는 extend 사용

    # MySQL 연결 객체 생성
    myConn = pymysql.connect(user='???', password='???', host='localhost', port=3306,
                             charset='utf8', database='MYTRDDB')
    myCursor = myConn.cursor()
    for stk in stk_master_all:
        sql_ins = "INSERT INTO MYTRDDB.KRX_STOCK(STK_CD ,STK_NM ,MKT_NM) VALUES(%s, %s, %s)"  # INSERT SQL 작성
        myCursor.execute(sql_ins, (stk[0], stk[1], stk[2]))  # 튜플 형태로 파라미터 전달해서, SQL 실행

    # COMMIT 처리 및, MySQL 개체 CLOSE
    myConn.commit()
    myCursor.close()
    myConn.close()

    print('작업 완료')

 

위 파이썬 소스를 실행한 후에, MySQL에 접속해, 아래와 같이 SQL을 실행해보면, 주식 마스터 정보가 자신의 DB에 만들어진 것을 확인할 수 있습니다.

SELECT  T1.*
FROM    MYTRDDB.KRX_STOCK T1
ORDER BY T1.STK_CD LIMIT 5;

STK_CD   STK_NM            MKT_NM   
-------- ----------------- -------- 
000020   동화약품          KOSPI    
000040   KR모터스          KOSPI    
000050   경방              KOSPI    
000060   메리츠화재        KOSPI    
000070   삼양홀딩스        KOSPI

 

오늘은 여기까지입니다.

MySQL을 사용해 주식 데이터베이스를 관리합니다.

MySQL 설치 과정은 아래를 참고해주세요. 저는 네이버 클라우드 서버에 MySQL을 설치했습니다.

  - https://sweetquant.tistory.com/230

 

2.2 MySQL 8 설치하기

여기서는 Windows 기준으로 MySQL 8을 다운로드하고 설치하는 과정을 설명한다. (MySQL은 5.7 버전에서 5.8 버전으로 올라가면서 MySQL 5.8이 아니라 MySQL 8로 부르고 있다.) MySQL 8이 이미 설치되어 있다면,

sweetquant.tistory.com

 

MySQL에 root 권한으로 접속해 (Workbench와 같은 툴을 사용하면 됩니다. 아래와 같이 주식 데이터를 관리하기 위한 데이터베이스를 생성합니다.

여기서는 DB_TRDOPTIM이라는 DB명을 사용했습니다.

CREATE DATABASE DB_TRDOPTIM;

 

추가로, 네이버 클라우드 외부에서 윈도우즈 터미널(mstsc)이 아닌, MySQL에 바로 접속하기 위해서는, 네이버 클라우드에서 공인IP를 설정해야 합니다.(이또한 비용이 추가됩니다. 월 5천이 조금 안되는 금액이네요.ㅜㅜ)

공인IP는 사용량 상관없이 고정비 같습니다. 나중에 자원 회수 할때 까먹지 않고 폐기해야 할거 같네요.

 

아래 메뉴에서 공인IP를 추가할 수 있습니다.

- https://console.ncloud.com/server/publicIP

 

 

공인IP를 추가한 후에는 해당 공인IP에 MySQL에 접속할 수 있는 포트를 열어줘야 합니다. 아래의 ACG 메뉴에서 설정이 가능합니다. 접근 소스를 0.0.0.0/0 (전체)로, 허용 포트를 3306(MySQL 기본 포트)를 설정해줍니다.

https://console.ncloud.com/server/acg

 

외부에서 클라우드 환경 MySQL 서버에 바로 접속하려면 추가로, MySQL 계정을 생성해야 합니다.

터미널 상에서 MySQL에 접속해 아래와 같이 사용자를 추가합니다. 위에서 만든 DB_TRDOPTIM DB에 권한도 부여해 줍니다.

     CREATE USER 'USR_TRDOPTIM'@'%' IDENTIFIED BY '패스워드';
     GRANT ALL ON DB_TRDOPTIM.* TO 'USR_TRDOPTIM'@'%';

 

이제, 개인 PC에서 MySQL Workbench를 사용해 클라우드 상의 MySQL에 접속이 가능해집니다.

아래와 같이 Default Schema를 DB_TRDOPTIM으로 설정해줍니다.

 

트레이드 옵티마이져를 개발하기 위해, 네이버 클라우드 환경을 사용할 예정입니다.

당연히!! 네이버 클라우드에 서버를 생성하는 것은 비용이 듭니다.

하지만, 사용하는 만큼만 비용을 내면 된다는 점, 그리고 구성과 관리가 편하다는 점에서 클라우드 사용을 추천하는 편입니다.

 

1. 네이버 클라우드에 접속해 회원 가입을 합니다.

    - https://www.ncloud.com/

 

NAVER CLOUD PLATFORM

cloud computing services for corporations, IaaS, PaaS, SaaS, with Global region and Security Technology Certification

www.ncloud.com

 

2. 네이버 클라우드 콘솔에 접속합니다.

    - https://console.ncloud.com/server/server

 

3. Server 메뉴에 접속헤 서버를 생성합니다.

    - 2세대 서버를 사용합니다.

 

4. 서버 이미지를 선택합니다.

    - 100GB, Windows, Standard를 사용했고, win-2016-64를 사용했습니다.

 

5. 서버 설정을 진행합니다.

    - 처리 속도를 고려해 조금 더 비싸지만 SSD를 사용합니다.

    - 서버 이름은 각자 정하면 됩니다.

 

6. 인증키 설정

    - 인증키 이름을 입력하고 '인증키 생성 및 저장'을 진행합니다.

    - 해당 인증키를 사용해 터미널 접속 암호를 확인할 수 있습니다.

 

7. 네트워크 접속 설정

    - 그냥 넘어가면 됩니다.

 

8. 최종 확인

    - 최종 확인을 합니다. 이제 확인하면 서버가 만들어집니다.

 

   

9. 서버 터미널 암호 확인하기

    - 아래 URL에  들어갑니다.

    - https://console.ncloud.com/server/server

    - 서버 목록에 마우스 우클릭 - 관리자 비밀번호 확인을 선택합니다.

    - 해당 메뉴에서 위에서 받은 인증키를 첨부해 관리자 비밀 번호를 확인합니다.

 

10. 포트 포워딩 설정

     - 외부에서 서버에 접속할 수 있도록 포트 포워딩이 필요합니다.

     - 서버 콘솔 메뉴에서 서버를 선택한 후에, 포트포워딩을 클릭합니다.

     - IP와 포트 번호를 잘 기억합니다.

 

11. 원격 데스크톱 연결(터미널) 프로그램을 이용해 접속합니다.

      - 윈도우즈에서 mstsc를 검색해 실행하면 됩니다.

      - 암호는 앞에 9번 단계에서 얻은 어드민 암호를 사용하면 됩니다.

 

 

 

여기까지 하면, 네이버 클라우드에 윈도우즈 서버 생성및 접속까지 완료가 됩니다.!

 

 

앞에서 아나콘다 가상 환경을 설정했습니다.

 

Anaconda 가상 환경 만들기

파이썬은 다양한 라이브러리(모듈 또는 패키지)를 사용할 수 있는 것이 장점입니다. 하지만, 라이브러리 버젼이 너무 많고 다양하다 보니, 여러 프로젝트에 하나의 환경을 사용하다 보면, 문제

sweetquant.tistory.com

 

아나콘다 가상 환경을 사용하는 프로젝트에서 파이썬 라이브러리를 추가해서 사용하기 위해서는

아나콘다 가상 환경에 진입해 라이브러리를 추가하애 합니다.

우선, 위의 글에서처럼, 'Anaconda Prompt'를 실행합니다.

그 다음에 conda env list 를 실행해 가상 환경 리스트를 조회합니다.

conda env list

 

위 결과를 통해 어떤 가상 환경들이 있는지 확인할 수 있습니다. 조회된 가상 환경 중에 우리가 만들었던 python37_64bit_mystktest 가상 환경에 진입해봅니다. 아래와 같이 conda activate를 실행하면 됩니다.

conda activate python37_64bit_mystktest

 

가상 환경인 python37_64bit_mystktest에 진입했으므로, pip를 이용해 필요한 라이브러리(모듈, 패키지)을 설치하면 됩니다. 여기서는 requests를 설치해봅니다.

pip install requests

 

아나콘다 가상 환경에 라이브러리 설치하는 과정을 살펴봤습니다. 이상입니다.

 

Trade Optimizer(트레이드 최적화기)

주식 매매 또는 투자에 최적화된 방법을 찾기 위한 개인적인 프로젝트입니다.

MySQL, Python(Anaconda + Pycharm)을 결합한 데이터 분석 프로젝트로서 천천히 준비중입니다.

Trade Optimizer에서는 아래와 같은 글들을 올립니다.

  • Trade Optimizer를 구축해가는 과정
  • 파이썬 데이터 수집 기술
  • 파이썬 기초 기술
  • 파이썬, SQL 데이터 처리 기술
  • 파이썬, SQL 데이터 분석 기술
  • 트레이드 최적화된 결과
    • 특정 종목을 추천하거나 투자/매매를 권장하기 위한 글이 아닙니다.
    • 개인적으로 분석한 주식 종목을 기록 차원에서 올릴 예정입니다.
    • 본 카테고리 글을 참고해 투자한 경우, 결과에 대해서는 그 누구도 절대 책임지지 않습니다.

본 글에서는 Anaconda와 Pycharm 조합으로 파이썬을 사용합니다.

 

기초 단계라 할 수 있는 Anaconda 및 Pycharm 설치, 'Hello Python' 실행해보기 까지는 아래 글을 참고해주세요.

 

기본적인 환경(Anaconda 설치, Pycharm 설치, Anaconda 가상환경, Pycharm 신규 프로젝트)을 완료했다면, 이제 간단한 'Hello Python'을 하나 만들어 보겠습니다.

앞에서 만든 MyStkTest 프로젝트를 엽니다. 아래와 같은 순서로 새로운 파이썬 파일을 생성합니다.

  • 왼쪽의 Project 창의 MyStkTest에서 마우스 우클릭
  • 팝업 메뉴에서 New 선택
  • 팝업 메뉴에서 Python file 선태
  • New Python file 창에 '000_HelloPython' 이라고 입력하고 엔터를 누릅니다.

 

HelloPython 파일이 만들어졌으면, 해당 파일에 간단한 Print 코딩을 작성합니다. 아래 그림을 참고해서 진행하시면 됩니다.

  • 000_HelloPyhon.py 선택
  • 코딩 창에 아래 내용을 입력
    • print('Hello Python')
  • 코딩 창, 빈 공간에 마우스 우클릭하면 팝어 메뉴가 나옵니다.
    • 팝업 메뉴에서 Run '000_HelloPyhon' 을 선택
  • 아래쪽 창에 결과가 나온 것을 확인할 수 있습니다.

 

아주 간단한 파이썬 프로그램을 만들어 실행해봤습니다.

 

 

 

 

Pycharm에서 'MyStkTest'라는 신규 프로젝트를 만들어보겠습니다.

윈도우즈에서 Jetbrains의 Pycharm을 찾아 실행합니다. 아래 그림을 참고합니다.

 

아래와 같은 Welcome 창이 나오면, New Project를 선택해주세요.

 

아래 그림과 같은 New Project 창이 나오면, 아래 순서대로 작업을 진행합니다.

  • Location에 'MyStkTest' 를 입력
  • Previsoulsy configured interpreter를 선택
  • Add Interpreter 클릭 / Add local Inpterpreter 선택
    • 여기서, 앞에서 만든 conda 가상 환경을 설정합니다.

 

Add Local Interpreter에서 아래와 같이 앞에서 설정한 가상 환경을 선택하고 'OK'를 누릅니다.

 

아래와 같이 환경이 설정되었으면, 'Create'를 클릭해 MyStkTest 프로젝트를 생성합니다.

여기까지 진행하면, 코딩을 위한 기본적인 준비가 끝났네요.

 

 

 

 

 

 

 

 

파이썬은 다양한 라이브러리(모듈 또는 패키지)를 사용할 수 있는 것이 장점입니다.

하지만, 라이브러리 버젼이 너무 많고 다양하다 보니, 여러 프로젝트에 하나의 환경을 사용하다 보면, 문제가 발생할 가능성이 있습니다. 그러므로 프로젝트별로 하나의 가상 환경을 만들어 처리하는 것이 좋습니다.

본 글은 아래 내용을 참고했습니다.

  - https://hyunlee103.tistory.com/58

 

Anaconda + 파이참(Pycharm), 가상환경 구축하고 연동하기

맨날 colab에서만 코딩을 하다가 파일이 많아지고 정리가 어려워 IDE를 사용하기로 했다. colab은 도커 환경이라 내가 따로 환경 설정을 해주지 않아도 되고 필요한 패키지들도 거의 다 설치되어 있

hyunlee103.tistory.com

 

1. Anaconda Prompt 실행

가상 환경을 생성하기 위해 아나콘다 프롬프트를 실행합니다.

  - 설치된 프로그램 중에 Anacond3 (64-bit)Anaconda Prompt (Anaconda 3) 을 실행(아래 그림 참고)

 

 

2. Anaconda Prompt에서 가상 환경 생성

아래와 같이 입력해 'python37_64bit_mystktest' 라는 가상 환경을 생성합니다. 파이썬 버젼을 3.7을 사용하도록 설정했습니다.

  - conda create -n python37_64bit_mystktest python=3.7

  - 아래와 같이 나오면 y를 눌러주시면 됩니다.

 

 

3. 가상 환경 관련 prompt 명령어

Anaconda prompt에서 아래와 같은 명령어들을 사용할 수 있습니다.

  • conda env list : 콘다 가상환경 리스트 확인
  • conda activate python37_64bit_mystktest : 가상환경 진입
  • conda deactivate : 콘다 가상환경 빠지기

여기까지입니다. 다음에는 파이참에서 가상환경을 사용해 프로젝트를 만들어보도록 하겠습니다.

 

 

 

파이썬 개발 툴 중 하나인 Pycharm을 설치합니다.

앞에서 설치한 Anaconda와 연동해서 사용하게 됩니다.

  - https://sweetquant.tistory.com/354?category=1314904 

 

아래 경로에서 무료로 사용할 수 있는 커뮤니티 에디션을 다운로드합니다.(아래 경로는 윈도우즈용입니다.)

  - https://www.jetbrains.com/ko-kr/pycharm/download/#section=windows

 

다운로드 PyCharm: JetBrains가 만든 전문 개발자용 Python IDE

 

www.jetbrains.com

 

다운로드 받은 아래 파일을 실행합니다.(다운로드 시점에 따라 버젼과 파일명은 다를 수 있습니다.)

  - pycharm-community-2022.2.3

 

파이참 설치 역시 아나콘다처럼 대부분 Next만 눌러주시면 됩니다. 특별히 어려운거 없으므로 넘어갑니다.

 

 

 

 

파이썬을 사용해 주식 데이터를 수집 및 분석하기 위해 아나콘다, 파이참, MySQL 설치가 필요합니다.

 

우선은 아나콘다를 설치합니다. 다음 경로에서 아나콘다를 다운로드합니다.

 - https://www.anaconda.com/products/distribution

 

Anaconda | Anaconda Distribution

Anaconda's open-source Distribution is the easiest way to perform Python/R data science and machine learning on a single machine.

www.anaconda.com

 

 

예전에는 윈도우즈용은 32bit, 64bit 버젼이 별도로 있었으나,현재는 64bit에서 32bit를 하위호환하도록 구성되어 있는거 같습니다. 키움API를 위해서는 32bit용이 필요합니다. 이 경우 64bit의 아나콘다에서 별도 가상 환경 설정이 필요합니다. 아래 글을 참고해주세요.

  - https://hyunlee103.tistory.com/58

 

Anaconda + 파이참(Pycharm), 가상환경 구축하고 연동하기

맨날 colab에서만 코딩을 하다가 파일이 많아지고 정리가 어려워 IDE를 사용하기로 했다. colab은 도커 환경이라 내가 따로 환경 설정을 해주지 않아도 되고 필요한 패키지들도 거의 다 설치되어 있

hyunlee103.tistory.com

 

윈도우즈용 최신 버젼을 다운로드합니다. 저 같은 경우 2022.10 버젼을 받아서 설치했습니다. 아래 파일을 받아서 실행합니다.

  - Anaconda3-2022.10-Windows-x86_64

 

별다른 거 없이 Next(다음) 버튼만 누르면 설치가 완료됩니다.

 

 

+ Recent posts