2016년 7월 14일 목요일

주가 분석 , 이평선 골든 크로스, 볼린져 밴드 하단 터치 이후 상승, MACD signal Cross 종목 찾기

https://github.com/sparrowapps/systemt

2016년 7월 14일 골든 크로스 결과만 보자면

sqlite> select * from MAGC;
0|A004560|현대비앤지스틸
1|A175330|JB금융지주
2|A004960|한신공영
3|A900110|이스트아시아홀딩스
4|A085310|엔케이
5|A000155|두산우
6|A016880|웅진
7|A059090|미코
8|A200780|비씨월드제약
9|A082740|두산엔진
10|A110570|넥솔론
11|A100030|모바일리더
12|A160550|NEW
13|A027050|코리아나
14|A083450|GST
15|A089600|나스미디어
16|A041440|에버다임
17|A200230|텔콘
18|A090990|코리아03호
19|A065440|이루온
20|A079650|서산
21|A008700|아남전자
22|A024120|KB오토시스
23|A050760|에스폴리텍
24|A008970|동양철관

sqlite> 

네이버님의 골든크로스 결과보다 몇몇 종목이 더 나 왔다.


#-*- coding: utf-8 -*-

import pandas as pd
from pandas import Series, DataFrame
import sqlite3

import numpy as np

from logger import get_logger
from stockcode import get_code_list
from settings import START_DATE
from cp_constant import *
import win32com.client

def checkData( cursor, table_name ):
    row = cursor.execute("SELECT 1 FROM sqlite_master WHERE type='table' AND name='{}'".format(table_name)).fetchone()
    if row is None: return False
       
    row = cursor.execute("SELECT COUNT(*) FROM '{}'".format(table_name)).fetchone()
    if row is None : return False

    return True

def makeDataFrame( code ):
    with sqlite3.connect("price.db") as con:
        cursor = con.cursor()
        table_name = code
       
        if checkData( cursor, table_name ) == False: return False
       
        df = pd.read_sql("SELECT * FROM '{}'".format(table_name), con, index_col=None)
        return df

def isMAGoldCross( df, MA1 = 20, MA2 = 60 ):
    df['short_ma'] = pd.rolling_mean(df['CLOSE'],MA1)
    df['long_ma'] = pd.rolling_mean(df['CLOSE'],MA2)
    df['signal'] = 0.0
       
    if len(df) < MA2 * 4 : return False
       
    df['signal'][MA1:] = np.where(df['short_ma'][MA1:] > df['long_ma'][MA1:], 1.0, 0.0)
    df['positions'] = 0.0
    df['positions'] = df['signal'].diff()
       
    if df['signal'][len(df)-1] == 1 and df['positions'][len(df)-1] == 1:
        return True
    else:
        return False

def isBBandSignal( df, period = 20):
    df['Bol_upper'] = pd.rolling_mean(df['CLOSE'], window=period) + 2* pd.rolling_std(df['CLOSE'], period, min_periods=period)
    df['Bol_lower'] = pd.rolling_mean(df['CLOSE'], window=period) - 2* pd.rolling_std(df['CLOSE'], period, min_periods=period)
    df['signal'] = 0.0
    df['signal'] = np.where(df['Bol_lower'] > df['CLOSE'], 1.0, 0.0)
    df['positions'] = 0.0
    df['positions'] = df['signal'].diff()

    if len(df) < 2: return False

    if df['signal'][len(df)-2] == 1 and df['positions'][len(df)-2] == 1:
        if df['signal'][len(df)-1] == 0 and df['positions'][len(df)-1] == -1.0:
            return True
        else:
            return False
    else:
        return False

def isMACDSignal( df, n1 = 12, n2= 26, c= 9):
    df['MACD'] = pd.ewma(df['CLOSE'], span=n1) - pd.ewma(df['CLOSE'], span=n2)
    df['MACD_Signal'] = pd.ewma(df['MACD'], span=c)
    df['signal'] = 0.0
    df['signal'] = np.where(df['MACD'] < df['MACD_Signal'], 1.0, 0.0)
    df['positions'] = 0.0
    df['positions'] = df['signal'].diff()

    if df['signal'][len(df)-1] == 1 and df['positions'][len(df)-1] == 1:
        return True
    else:
        return False

def run():
    with sqlite3.connect("analyze.db") as con:
        cursor = con.cursor()

        code_magc = {'CODE':[],
                     'NAME':[]}
        code_bb   = {'CODE':[],
                     'NAME':[]}
        code_macd = {'CODE':[],
                     'NAME':[]}

        for code, name in get_code_list():
            df = makeDataFrame( code )
            res = isMAGoldCross( df, 20, 60 )
            if res == True:
                code_magc['CODE'].append(code)
                code_magc['NAME'].append(name)
                get_logger().debug("MA20, MA60 Golden Cross {}{}".format(code,name))

            res = isBBandSignal( df, 20 )
            if res == True:
                code_bb['CODE'].append(code)
                code_bb['NAME'].append(name)
                get_logger().debug("BBnad lower after up {}{}".format(code,name))

            res = isMACDSignal( df, 12, 26, 9)
            if res == True:
                code_macd['CODE'].append(code)
                code_macd['NAME'].append(name)
                get_logger().debug("MACD sig {}{}".format(code,name))

        magc = DataFrame(code_magc)
        bb   = DataFrame(code_bb)
        macd = DataFrame(code_magc)
        magc.to_sql("MAGC", con, if_exists='replace', chunksize=1000)
        get_logger().debug("MAGC {} saved.".format(len(magc)))
        bb.to_sql("BB", con, if_exists='replace', chunksize=1000)
        get_logger().debug("BB {} saved.".format(len(bb)))
        macd.to_sql("MACD", con, if_exists='replace', chunksize=1000)
        get_logger().debug("MACD {} saved.".format(len(macd)))

if __name__ == '__main__':
    run()

python pandas_datareader yahoo 파이낸스 삽질기


코스콤에서 주식 코드를 얻어다가 yahoo 파이넨스에 pandas를 이용해서 주가 데이터를
가져 와서 sqlite  데이터를 구축 하려고 했다.

이렇게 가져온 데이터를 다시 pandas 데이터 프레임으로  sqlite로 부터 읽어 들여 분석을
하면 이동평균선 골든 크로스 등을 찾아 낼 수 있을 거라 생각 했다.

그런데 이상하게 동원이란 종목이 분석에 문제를 일으킨다.


>>> import pandas_datareader.data as web
>>> df = web.DataReader("003580.KS", "yahoo", "2016/06/01", "2016/07/13")
>>> print (df)
            Open  High   Low  Close  Volume  Adj Close
Date                                                
2016-06-01  1854  1854  1802   1814   45100       9070
2016-06-02  1866  1866  1804   1830   35200       9150
2016-06-03  1850  1874  1792   1854   31100       9270
2016-06-06  1854  1854  1854   1854       0       9270
2016-06-07  1840  1878  1822   1846   22900       9230
2016-06-08  1846  1846  1784   1814   26700       9070
2016-06-09  1780  1868  1780   1856   46500       9280
2016-06-10  1834  1870  1800   1832   20900       9160
2016-06-13  1800  1828  1772   1812   17700       9060
2016-06-14  1780  1800  1680   1758   25400       8790
2016-06-15  1740  1812  1724   1732   16600       8660
2016-06-16  1720  1788  1694   1730   16700       8650
2016-06-17  1730  1738  1602   1644   34900       8220
2016-06-20  1630  1670  1620   1638   29200       8190
2016-06-21  1650  1668  1638   1656   11300       8280
2016-06-22  1626  1696  1626   1660    7400       8300
2016-06-23  1632  1666  1630   1660   14000       8300
2016-06-24  1666  1676  1450   1550   77000       7750
2016-06-27  1486  1626  1482   1626   37600       8130
2016-06-28  1580  1694  1564   1690   32400       8450
2016-06-29  1688  1738  1622   1690   24000       8450
2016-06-30  1660  1762  1660   1762   35200       8810
2016-07-01  1762  1780  1726   1780   19600       8900
2016-07-04  1768  1790  1742   1760    6300       8800
2016-07-05  1734  1778  1732   1758   14100       8790
2016-07-06  1740  1740  1684   1720   14300       8600
2016-07-07  1780  1780  1702   1740   12900       8700
2016-07-08  1720  1784  1698   1740   24700       8700
2016-07-11  8400  8660  7630   8030  268800      40150
2016-07-12  7850  8400  7850   8350  106900      41750
2016-07-13  8500  8500  8250   8300   40000      41500




위에서 데이터를 보면 7월 8일 까지 1700원 때이던 데이터가 갑자기 8400원대로 변경 된다.
문제가 있다.

거래량도 갑자기 증가 한다.

야후 파이낸스에 데이터를 믿을수가 없다.

문제는 또한 KOSDAQ종목은 데이터가 없다.

이는 구글 파이낸스도 마찬가지다.

하여 결국 대신 증권 API를 이용해서 코드 부터 주식 과거 데이터를 구축 하는 코드로 변경 하였다.


야후 파이낸스도 믿을게 못된다.


2016년 6월 9일 목요일

XCode swift "Command failed due to signal: Segmentation fault: 11 해결 방법

XCode swfit 컴파일러가 컴파일중에 세그먼테이션 폴트가 발생하면 어떻게 해결 해야 하는가?



어떤 라인이 문제가 있는지 어떤 코드가 문제인지 찾아 주지도 못한다.

심지어 이런 상황에서 버그를 리포트 하라고 에디터 상단에 아래와 같은 화면이 표시 되기도 한다.




에디터는 신텍스 하이라이트가 실행 되지 못하고 모든 텍스트가 흑백으로 표시 될때도 있다.





XCode의 버젼은 7.3.1이다.


문제의 코드는 위에 주석처리 한 코드 아래의 코드가 문제를 일으키는 코드이다.

recentlAddr은 아래와 같이 선언 되어 있다.

var recentlAddr = [[String:AnyObject]]()

if 문으로 바로 비교를 들어가면 Xcode swift 컴파일러가 문제를 일으키는 것으로 보인다.

더많은 케이스가 있겟지만 내가 찾은 케이스는 이런 경우 이다.

위에 올바른 코드와 같이 

func bookmarkButtonClick(sender : UIButton) {
        let bookmark = self.recentlAddr[sender.tag]["bookmark"] as! String
        
        if bookmark == "1" {
            return
        }
        recnetTobookmark(sender.tag, bookMarkType: 3)
    }

이렇게 수정하면 아무런 문제 없이 컴파일이 잘되고 문제가 없다.

결론
 XCode 컴파일러의 Segmentation fault 11이 발생하면 그래도 코드를 유심히 찾아 봐라!

2016년 6월 2일 목요일

iOS app에서 GCM (Google Cloud Messaging 사용하기

APNS를 위한 애플 개발자 페이지에서 앱 설정을 해야 한다.

구글 클라우드 메세징 서비스 페이지
https://developers.google.com/cloud-messaging/

구글 페이지에서
좌측 iOS를 선택하고 언어를 swift로 선택을 하여 안내를 받을 수 있다.

Cocoapod 을 이용해서 Google GCM 라이브러리를 프로젝트에 추가 해야 한다.

https://developers.google.com/cloud-messaging/ios/start?ver=swift


아래에 훌륭한 문서를 참조 하면 쉽게 따라 할 수 있다.
http://devlecture.tistory.com/entry/팁02-APNS-쉽게-만들고-테스트하기


Appdelegate 에 구글에서 제공하는 코드 뼈대를 잘 넣어 줘서 푸시를 수신 받을 수 있다.


앱이 포그라운드 상태에서 푸시를 받으면 아래에 메서드가 호출 된다.
 func application( application: UIApplication,
    didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
      print("Notification received: \(userInfo)")
      // This works only if the app started the GCM service
      GCMService.sharedInstance().appDidReceiveMessage(userInfo);
      // Handle the received message
      // ...
  }
 
앱이 백그라운드 상태에서 푸시를 받으면 아래에 메서드가 호출 된다.  
  func application( application: UIApplication,
    didReceiveRemoteNotification userInfo: [NSObject : AnyObject],
    fetchCompletionHandler handler: (UIBackgroundFetchResult) -> Void) {
      print("Notification received: \(userInfo)")
      // This works only if the app started the GCM service
      GCMService.sharedInstance().appDidReceiveMessage(userInfo);
      // Handle the received message
      // Invoke the completion handler passing the appropriate UIBackgroundFetchResult value
      // ...
  }
 
아래에 메서드는 GCM 서버로 부터 registrationToken을 받는다. 
  func registrationHandler(registrationToken: String!, error: NSError!) {
  }
 
테스트는 구글  크롬 어플리케이션 중에 포스트 맨을 이용하여 테스트가 가능 하다.

  registrationToken과 구글 GCM 사이트에서 앱을 등록 하고 p12 키등을 입력 받아서 얻은 Server API Key가 있어야 테스트가 가능 하다.



중요
디버깅 모드에서 푸시가 잘되는데 adhoc (릴리즈 버젼에서 푸시가 오지 않는경우)

개발이 완료되어 배포 시점이 되면 다음 코드를 수정 해야 한다.
  func application( application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken
      deviceToken: NSData ) {
  // [END receive_apns_token]
        // [START get_gcm_reg_token]
        // Create a config and set a delegate that implements the GGLInstaceIDDelegate protocol.
        let instanceIDConfig = GGLInstanceIDConfig.defaultConfig()
        instanceIDConfig.delegate = self
        // Start the GGLInstanceID shared instance with that config and request a registration
        // token to enable reception of notifications
        GGLInstanceID.sharedInstance().startWithConfig(instanceIDConfig)
        registrationOptions = [kGGLInstanceIDRegisterAPNSOption:deviceToken,
          kGGLInstanceIDAPNSServerTypeSandboxOption:true]
        GGLInstanceID.sharedInstance().tokenWithAuthorizedEntity(gcmSenderID,
          scope: kGGLInstanceIDScopeGCM, options: registrationOptions, handler: registrationHandler)
        // [END get_gcm_reg_token]
  }

kGGLInstanceIDAPNSServerTypeSandboxOption:true --> kGGLInstanceIDAPNSServerTypeSandboxOption:false

2016년 5월 21일 토요일

기아 uvo 2.0 사용기



현대에는 블루링크, 기아에는 uvo라는 이통사와 연계된 텔레메틱스 시스템이 있다.

2년간 무료 서비스이기에 사용중이다.

2년후에는 유료로 전환되는데 사용결정은 일단 그때로 미루고 최근 사용해본 소감을 나열 한다.

아이뻐 6s + 화면에서는 그냥 UI가 커진 화면으로 나와서 좀 어색 하지만 딱 필요한 기능만 넣은 간단한 UVO앱으로 uvo 서비스를 제공 한다.

가장 좋은 기능은 네비게이션에게 목적지를 전송 하는 기능
출발전 아이폰으로 목적지를 검색하고 전송한 후 차에서 네비게이션을 확인 하여 전송 받은 목적지를 선택 하여 목적지로 설정 할 수 있다.

그리고 점점 더워지는 요즘 날씨에 꼭 필요한 원격시동
어릴적 아버지 자동차에 사제 원격시동 장치는 기어가 들어가 있음에도 시동이 걸려 주차한 상태에서 다른 차를 받아 버리는 어처구니 없는 사고가 일어 났었지만..... 쩝

설마 그런 버그는 없겠지...?  그리고 기어를 넣고 시동을 끄면 머 경고 해주니.. 설마 그럴일은 없을 거야? 나름 안심 하고 사용 한다.

원격시동은 미리 설정한 공조 장치 (에어컨 온도) 등이 작동 하면서 시동이 걸려 요즘 처럼 날씨가 더워지는 시기에 아주 좋은 기능 같다. 겨울에도 디젤차의 경우 예열이 필요 하니 유용 할 듯 하다.

그밖에 항상 내차의 문은 잠겨있는지? 주차는 어디에 했는지? 요정도의 기능이 있어 좋다.
그리고 어떤 식으로 동작 하는지는 모르지만 기아 레드 멤버스 웹페이지에 로그인 해보면
내 차량 정보와 현재 주행 거리 ( 하루 정도 전) 의 거리가 표시 된다. 차량 내부에 uvo 단말기가 기아 서버에 현재 주행 거리를 주기적으로 sms로 전송 하는 것으로 보인다.

좀 아쉬운 점이라면 앱의 GUI가 좀 예쁘지 않다는거? 아이폰 6s+에서 그냥 UI가 커진 이미지는 정말 좀 아쉽다.

uvo 자체가 자동차에 있는 단말기에 전화를 걸어서 처리 하는 것으로 보이는데 동작 속도가 좀 오래 걸린다는거? 문잠금 정도 확인 하는데도 20여초가 걸리니 좀 성질 급한 나는 좀 아쉽다.

그래도 2년 동안 이러한 기능들을 무료로 사용 할 수 있어서 좋다.
이밖에도 불의의 사고로 에어백이 전개 되거나 차량 추돌이 감지 되었을때 긴급 SOS기능으로 보험사 등에 연락을 한다는 것도 좋은 기능 같다.



2016년 5월 11일 수요일

블랙박스 CR-500HD 베터리 교체 하기

2009 투싼ix에서 사용하던 블랙박스 파인뷰의 CR-500HD 상당이 고가의 블랙박이다.
화질 좋고 야간 촬영도 어둡지 않고 시인성이 좋다.

학교 선배 형님이 장착 해주신건데 너무 고가 이지만 장착 후  사고 하나를 잡아내서 몸값은 했다.
그러나 이 블랙박스의 치명적인 결함이 있으니 내장 베터리가 2년이면 고장이 난다.

내장 베터리가 고장이나면 메번 부팅시마다 시간설정을 확인 하라는 메세지가 나오고
저장된 동영상은 모두 날짜가 뒤죽 박죽 되어 있다.

http://ttlshome.tistory.com/335

http://blog.daum.net/_blog/BlogTypeView.do?blogid=0Zv3l&articleno=86&categoryId=0&regdt=20140914145225

위 링크는 모두 이런 문제 때문에 자가 교체 하는 내용이다.

고장이 난지 벌써 2년이 흘렀지만 그냥 그냥 내비 둿다.
베터리까지 사서 교체 하기는 너무 힘들고 어려울듯 해서였다.

투싼ix를 처분하면서 CR-500HD를 차량에서 떼어 냈다.
그리고 알바로 작업했던 하드웨어에 비슷한 모양에 베터리가 있길래 위 링크를 참조해서 직접 분해하고 베터리를 교체 해 보았다.

결론
잘된다.

아파트 베란다에 지상 주차장 감시용 CCTV나 맨드러야 겠당!