파이썬은 참 좋은 언어인데, C나 C#같이 컴파일 방식이 아니라 인터프리터 방식이다보니 실제 코드가 실행되는 순간에 문법적인 오류가 발생하면 죽는 문제가 생깁니다. 컴파일 방식이라면 실행하기 전에 인지할 수 있겠지만 파이썬은 쉽지가 않습니다. 이 문제를 해결하기 위해서는 수정한 부분을 실제 조건을 만족시켜 돌려봐야하는데요. 이것도 쉬운 것은 아닙니다. 실제 조건문이 만족하도록 설정하는 행위가 소스를 수정하는 것이기 때문에 이 또한 문제를 야기할 수 있습니다.

 

이런 문제를 풀기 위하여 보통 유닛테스트를 많이 사용하는데요. 유닛테스트를 전체 프로그램을 test할 수 있으면 수정시 발생하는 오류를 가장 빨리 발견할 수 있습니다. 하지만 소스 전체를 유닛테스트로 적용하기 위해서는  최초 설계부터 반영을 해야하기 때문에 쉽지 않습니다.

 

결론적으로 유닛테스트를 적용하면 좋은데, 전체 소스코드에 적용하기에는 좀 어렵다인데요. 대안으로 특정 함수만 별도로 유닛테스트한 후 사용하는 것입니다.

 

이번에 주식 자동매매 프로그램을 만들던 중 매매 가격에 따라 유효한 주문 가격을 결정하는 함수를 유닛테스트를 적용한 예를 설명하도록 하겠습니다. 특히 주식 자동매매에서 유효한 주문가격을 구하지 못하면 주문 거부가 발생하기 때문에 꼼꼼하게 test해보아야 합니다. 모든 case를 손으로 직접 test하는 것은 쉬운 일이 아니기 때문에 유닛테스트를 적용하는 것이 바람직 합니다. 특히 해당 함수 내부 소스가 변경되는 경우에는 유닛테스트의 진가가 발휘됩니다.

 

올해 변경된 주식 가격별 호가 단위입니다. 자동매매 코드에서는 소숫점 계산을 한 목표 매수가가 나오고 이를 버림/반올림/올림 등의 조건을 추가하여 호가 단위에 맞는 가격으로 변경해주는 함수가 필요합니다.

우선 아래 package를 import합니다.

 

import unittest

 

그리고 원하는 함수를 작성합니다. 일단 2천원 미만은 1원 단위의 가격을 돌려주는 함수를 만들어봅시다. 

 

def get_order_price(price) :
    tick_size = 0
    if price < 2000:
            tick_size = int(price)
    return tick_size


다음은 unittest를 사용하는 방법입니다. unittest에서는 아래와 같은 CustomTests class를 지원합니다. 원하는 함수안에 필요한 코드를 넣으면 됩니다. test case는 test_process_statement() 함수 안에서 작성하면 됩니다.

 

 

 

class CustomTests(unittest.TestCase): 
    def setUp(self):    # 무시
        pass
    def tearDown(self): # 무시
        pass
    def test_process_statement(self) :
        in_price = 45
        result = get_order_price(in_price)
        self.assertEqual(result, 45) # 계산 결과와 원하는 값 입력

 

위와 같이 test_process_statement() 함수 안에 test case를 만들면 됩니다. 그 후 unittest.main()을 호출하면 계산값과 원하는 결과가 틀리면 self.assertEqual함수에서 fail이 뜹니다.

 

unittest.main()

 

실행을 해보면 아래와 같은 결과 나옵니다.

 

 

만약 in_price와 다른 값을 입력한다면

 

    def test_process_statement(self) :
    	in_price = 45
        result = get_order_price(in_price)
        self.assertEqual(result, 44) # 계산 결과와 다른 값 입력

 

친절하게도 틀리다는 메세지가 출력됩니다.

 

 

다음은 주식 거래시 사용하는 실제 코드입니다. 이번 전략에서는 목표 가격이 오면 가능한 빨리 매수하기를 원하기 때문에 버림을 적용합니다. float를 int로 변경하기만 하면 자동으로 버림이 적용되기 때문에 간단하게 구현할 수 있습니다.

 

def get_order_price(price):
    tick_size = 0.0
    if price >= 500000:
        tick_size = int(price/1000)*1000
    elif price >= 100000:
        tick_size = int(price/500)*500
    elif price >= 50000:
        tick_size = int(price/100)*100
    elif price >= 10000:
        tick_size = int(price/50)*50
    elif price >= 5000.0:
        tick_size = int(price/10)*10
    elif price >= 1000.0:
        tick_size = int(price / 5)*5
    else:
        tick_size = int(price)
    return tick_size

 

위 코드를 바탕으로 test case를 만들어보면 아래와 같습니다. 이외에도 모든 가격대를 test하는 문장을 추가하여야합니다.

 

    def test_process_statement(self) :
        result = get_order_price(999.99) # 1000원 미만 test
        self.assertEqual(result, 999)

        result = get_order_price(1000.01) # 1000원 이상 test
        self.assertEqual(result, 1000)

        result = get_order_price(4999.9999) # 5000원 이하 test
        self.assertEqual(result, 4995)

        result = get_order_price(9999.9999) # 10000원 이하 test
        self.assertEqual(result, 9990)

 

 

실행결과는 아래와 같습니다. 즉 문제가 없다는 의미입니다.

 

 

만약 함수의 출력과 예상결과가  틀린 경우에는 오류 메세지가 뜹니다. 오류 메세지가 뜨면 해당 가격에 대한 코드를 자세하게 살펴보면서 문제점을 수정하면 됩니다.

 

 

이렇게 완성된 함수를 본 프로그램에 추가하여 개발을 진행하면 됩니다. 모든 함수를 유닛테스트하기에는 시간이 많이 걸리는 문제가 있으므로, case가 복잡하거나 경우의 수가 많은 함수를 만드는 경우에는 해당 함수만 뽑아서 유닛테스트 환경하에서 test하는 습관을 들이는 것이 좋을 듯 합니다. 당장은 힘들겠지만 시간이 가면 갈수록 코드의 안정성을 유지하는 것이 유닛테스트 통과한 코드입니다.

 

반응형

설정

트랙백

댓글

자동매매 프로그램을 개발하면서 시간이 많이 걸리는 것 중의 하나가 GUI 부분입니다. 주로 Qt5를 많이 사용하는데, API 혹은 예제를 보고 본인이 원하는 대로 코딩을 해야합니다. Qt5가 워낙 파워풀하고 많이 사용되는 GUI 툴이므로 시간이 된다면 익숙해지는 것이 좋습니다.

 

하지만 본 카페에 계신 많은 분들이 개발을 배우고 계신 상태이다보니 Qt5를 이용한 GUI는 말처럼 쉽지가 앖습니다. 저 또한 Qt5를 자주 사용하지 않다보니, 뭔가를 하려면 일단 긴장부터 하는데요.

 

그래서 간단하게 x, y 위치 주고 화면에 보일 text를 전달하면 화면에 보이는 아주 심플한 package가 없을지 찾아보았습니다. 옛날 dos 시절에 이런 식으로 화면을 디자인했었죠.

 

오늘 소개해드릴 tkinter가 바로 제가 원했던 심플 GUI package입니다.

 

일단 화면부터 보시죠

 

 

 

현재 선물 가격 표시하고(상승/하락에 따라 배경색도 바꿀 수 있음) 양매수 혹은 양매도 하고 있다면 현재가 양합과 수익을 화면에 보여주고 있습니다.

 

사용법은 아주 간단합니다. tkinter를 기반으로 사용하기 쉽게 wrapper 함수를 몇 개 정의하였습니다. 이를 이용하여 첫 번째 선물과 선물 가격을 화면에 출력하는 방법입니다.

 

    window = tk.Tk()
    window.geometry('620x680')

    # for 선물
    create_label(window, 10, 10, '선물', width=10) # (10,10)위치에 "선물" 출력 
    f_label = create_label(window, 80, 10, '', width=10) # (10,10)위치에 현재 선물 가격 출력할 label

    # 실시간 선물 현재가를 받은 후 출력하는 부분
    f_val = 312.44
    update_label(window, f_label, f_val, background='red') # 현재 선물가격 출력
 

 

create_label은 그냥 단순 label을 만드는 함수입니다. x,y 위치, 출력할 데이터, 넓이만 입력하면 됩니다.

그리고 선물 가격을 출력할 label도 별도로 만들어야 합니다. 이 또한 x,y 위치와 넓이만 입력하면 됩니다. text는 향후 update될 예정이므로 그냥 ''을 입력하면 됩니다.

 

xing api에서 선물 가격을 얻은 후 미리 만든 label에 출력하는 방법입니다.

함수명은 update_label이고 사용 방법은 앞에서 만든 label, 출력할 값, 배경색(필요하다면) 입니다.

 

이 두 함수만으로도 다양한 곳에 원하는 값을 쉽게 출력할 수 있습니다. 이 보다 더 간단할 수는 없겠죠.

------------------------------

 

다음으로는 treeview입니다. excel같이 row, col 형식으로 자료를 출력해줍니다.

    # for 양매수
    width = 50
    heads = ['행사가', '매도가', '현재가', '행사가', '매도가', '현재가', '양합', '양합차', '수익']
    widths = [width] * len(heads) 
    widths[8] = 80 # 수익은 더 넓은 공간이 필요해서 변경함
            
    row = 1
    col = 9

    create_label(window, 10, 50, '양매도', width=10)  # (10,50)위치에 "양매도" 출력
    tr_view = create_table(window, 10, 70, row, col, heads, widths, background='#D3D3D3') # gray
 

treeview를 그릴 수 있도록 create_table() 함수를 만들었습니다.

table을 출력할 x,y 위치, table의 구성(row, col), table head에 출력할 문자열, 각 문자열의 넓이, 마지막으로 table의 총 넓이를 입력으로 주면 됩니다.

이때 row는 title을 제외하고 date가 들어가는 row 수를 적으시고, 만약 화면에 보이는 treeview의 넓이가 column 보다 너무 넓으면 width=100 이런 식으로 전체 treeview의 넓이를 지정할 수도 있습니다.

 

추가적으로 필요한 기능이 있습니다. 예를들어 특정 column의 문자열 색을 바꾼다거나, 배경을 바꾸어야할 수도 있습니다. 이런 경우에는 해당 예제와 아래에 있는 문서를 참고하여 sample을 수정하여 사용하시면 됩니다.

 

 

-------------------------------

마지막으로 xing api와 연동하여 실시간으로 양합 값을 update하기 위해서는 thread를 사용하여야합니다. thread를 포함한 예제는 차후에 코드 정리해서 올리도록 하겠습니다.

 

-------------------------------

방금 설명한 tkinter sample 코드는 아래 github에 있습니다. pkinter 설치한 후 실행하시면 됩니다.

pip install pkinter
 
------------------------------
 
 

 

반응형

설정

트랙백

댓글

자동매매 프로그램을 돌리다보면 여러가지 이유로 종료되는 경우가 있습니다. 그 원인은 프로그램 자체 오류일 수도 있고, 사용하는 API 때문일 수도 있습니다. 자동매매를 돌리는 이유가 매매 시점을 빨리 찾기 위함인데 프로그램이 죽어있으면 아주 곤란합니다.

 

보통은 프로세서 id를 찾아서 잘 동작하는지 확인하는 방식으로 watchdog 프로그램을 만드는데요. 다행히 파이썬에서는 프로그램 단위로 동작 여부를 확인할 수 있는 방법이 있습니다. 바로 subprocess package를 사용하는 것입니다. 간단하게 call() 함수에 실행할 프로그램 명령어를 입력하면 됩니다.

import os 
import time 
from subprocess import call
cmd = 'python myprogram.py'

while(1) :
   call(cmd)
   time.sleep(30)

정상 동작한다면 return이 없이 계속 block되어 있고, 프로그램이 정상 혹은 비 정상으로 종료하면 return이 됩니다.

 

call은 popen이라는 함수의 특수한 사용 예입니다. 만약 프로그램을 실행시키고 다른 뭔가를 더 하고 싶다면 popen을 사용하시면 됩니다. 예를들어 terminal은 하나인데 여러 프로그램을 실행시켜야 한다면 popen을 사용하시면 좋습니다.

 

추가로 call 함수는 return 값이 있습니다. call 함수로 실행한 프로그램에서 정상 종료와 비 정상 종료를 return 값으로  구분할 수도 있습니다.

 

 

 

 

반응형

설정

트랙백

댓글

파이썬을 이용하여 app 개발할 때 유용한 package입니다.

 

1. pprint

dict, list 등 자료 구조에 있는 데이터를 구조에 맞쳐 출력을 해 줍니다.

<설치>

pip install pprint

 

<사용법>

from pprint import pprint 

pprint(변수명)

 

<예제>

from pprint import pprint 
cur_price = {
    'market':	"KRW-BTC",
    'trade_date':	"20220530",
    'trade_time':	"083351",
    'trade_date_kst':	"20220530",
    'trade_time_kst':	"173351",
    'trade_timestamp':	1653899631000,
    'opening_price':	37415000,
    'high_price':	38666000,
    'low_price':	37230000,
    'trade_price':	38475000,
    'prev_closing_price':	37380000,
    'change':	"RISE"
}
print(cur_price)
print('')
pprint(cur_price)

<실행결과>

 

2. log

프로그램 개발 중 저장할 내용을 기록할 수 있습니다.

 

<설치>

pip install logging

 

<사용법>

import time

import logging

 

# log 용 파일 정의하고 설정

log_name = '.\\test.log'
logging.basicConfig(filename=log_name, level=logging.INFO)

 

# 로깅이 필요한 곳에서 아래 함수 호출

logging.info(문자열)

 

<예제>

저장할 필요가 있는 곳에서 아래 함수를 부른다. 단 인자는 string 형태로 변경해 주어야 한다. 항목 마다 ,를 넣어서 향후 excel에서 csv 형태로 읽을 수 있도록 한다.

 

위 upbit거래소의 BTC 현재가 중 현재시간과 BTC 그리고  현재가를 저장하는 예제

 

cur = time.strftime("%Y%m%d") # 현재 시간
ss = cur + ',' + cur_price['market'] + ',' + str(cur_price['trade_price']) # 현재시간,krw-btc,현재가
logging.info(ss) # 저장

<결과>

파일에 저장된 결과입니다.

3. colored text

GUI를 이용하여 개발하기에는 시간이 많이 소요되므로 일반적으로 text용 terminal을 이용합니다. 이때 중요한 문자열에 서로 다른 색으로 표출할 수 있다면 가독성이 올라갑니다. 

 

<설치>

pip install termcolor

 

<사용법>

from termcolor import colored

 

colored() 함수를 이용하여 원하는 색이 입혀진 text를 받은 후 출력

 

<예제>

from termcolor import colored

data = 'SELL'
s = colored(data, 'red')
print('this is red', s)

data = 'BUY'
s = colored(data, 'cyan')
print('this is blue', s)

<실행결과>

반응형

설정

트랙백

댓글

파이썬 프로그램으로 프로그램을 개발하는 경우에는 cmd 창에 관련 메세지를 출력하는 경우가 많습니다.

이때 출력되는 text에 컬러를 입힐 수 있다면 가독성이 올라갈 수 있습니다.

 

관련 글들을 찾아보니 간단하게 아스키 문자열을 추가하면 원하는 color로 변경할 수 있습니다. 

 

우선 기본 컬러를 정의한 후

BRIGHT_BLACK = '\033[90m'
BRIGHT_RED = '\033[91m'
BRIGHT_GREEN = '\033[92m'
BRIGHT_YELLOW = '\033[93m'
BRIGHT_BLUE = '\033[94m'
BRIGHT_MAGENTA = '\033[95m'
BRIGHT_CYAN = '\033[96m'
BRIGHT_WHITE = '\033[97m'
BRIGHT_END = '\033[0m'

 

print 문에 아래와 같이 함께 출력하면 됩니다.

  print(BRIGHT_RED + 'TEST' + BRIGHT_END)

결과는 아래와 같습니다. 

 

출력 문자열 중 컬러를 변경하고 싶은 경우에는 앞에 색깔, 뒤에 END를 추가하면 됩니다.

조금 귀찮긴 하지만 간단하게 컬러 문자를 출력할 수 있군요.

함수로 만들어 쓰면 좋을 듯 합니다.

 

아래 글 참고했습니다.

https://happylie.tistory.com/119

반응형

설정

트랙백

댓글

프로그램 동작시 환경 변수를 읽어와야하는 경우가 많습니다. 주로 프로그램 실행에 관련된 parameter들이나 이전 프로그램 종료 전에 기록한 값 등입니다.

 

환경변수를 읽어오는 다양한 방법이 있겠지만 가장 간단한 방법은 json 형태로 text 파일에 저장하고, 이를 읽어오는 방법입니다.

 

아래는 간단한 예제입니다. 

 

제가 사용하는 자동 매매 프로그램에서 필요한 변수들입니다. 사용할 minute 캔들, MA 값, MACD 계산시 어떤 값을 사용할지, 갭보정을 할지 말지 등등을 미리 아래와 같은 형태로 text 파일로 저장해둡니다.

{
   "min_candle": 1,
   "ma": 120,
   "macd_diff_cal": "close",
   "fixing_gap": 1

}

이렇게 만들어진 json 형태의 txt파일을 읽어오는 코드입니다.

def load_json_from_file(file_name) :
    try :
        with open(file_name,'r',encoding="cp949") as make_file: 
           data=json.load(make_file) 
        make_file.close()
    except  Exception as e : # 또는 except : 
        data = {}
        print(e, file_name)
    return data

 

사용방법은 간단합니다. 그냥 함수 콜을 하면 json 형태의 자료 구조를 돌려줍니다.

 

my_param = load_json_from_file('my_param.txt')

 

만약 프로그램  중 상태 값을 저장하는 경우라면 별도 txt 파일을 사용해서 프로그램 중간 중간 값을 저장하면 됩니다. 저장할 때는 아래와 같이 현재 사용 중인 변수를 그냥 저장하면 됩니다.

 

save_to_file_json('cur_status.txt', cur_status)

 

def save_to_file_json(file_name, data) :
    with open(file_name,'w',encoding="cp949") as make_file: 
       json.dump(data, make_file, ensure_ascii=False, indent="\t") 
    make_file.close()

 

아래 파일은 upbit에서 코인 자동 매매를 하면서 현재 주문 중인 상태를 프로그램 실행 중에 저장하는 json 파일 내용입니다.

 

{
	"values": {
		"latest_tr_price": 3.33,
		"latest_tr_side": "ask"
	},
	"uuids": {
		"7caf5f1c-9c62-49c5-9f4f-090dcd862e7e": {
			"status": 1,
			"side": "bid",
			"org_qty": 500,
			"done_qty": "0.0",
			"price": 3.28
		}
	}
}

 

upbit의 경우에는 매매가 되었다는 event가 발생하지 않아서 이렇게 이전 매매 내역을 가지고 있다가 현재 해당하는 uuid가 없으면 매매가 되었다고 판단합니다. 만약 동작 중 알 수 없는 이유로 종료되었다가 다시 기동하는 중간에 매매가 이루어질 수 있습니다. 이런 경우를 찾기 위하여 기동시 status  파일을 읽어서 해당 uuid가 거래 중 상태인지 확인합니다. 만약 해당 uuid가 없다면 매매가 된 것이므로, 이에 상응하는 대응을 합니다.

 

정리하자면  프로그램 초기에 기동될 때 필요한 parameter 값을 json 형태로 text 파일에 저장하였다가 읽을 수 있습니다. 프로그램 중간 중간 혹은 종료시 필요한 상태 정보를 json 형태도 저장하였다가 이후에 다시 기동될 때 읽을 수 있습니다.

 

해당 함수는 아래 github에서 다운받으실 수 있습니다.

https://github.com/multizone-quant/system-trading-crypto-multi/blob/main/my_util.py

반응형

설정

트랙백

댓글

개발을 진행하다보면 날짜 시간 정보가 필요한 경우가 많습니다. 관련 package도 많이 있는 것으로 아는데, 일단 time, datetime을 이용하여 필요한 정보를 얻는 방법을 알아보겠습니다.

 

1. 초 정보

import time

print(time.time())

1970년 1월 1일 0시 0분 0초 이후 경과한 시간을 초단위로 알려줍니다. 

 

2. 날짜/시간 정보

현지 시간 기준으로 현재 날짜와 시간 정보를 얻을 수 있습니다.

tm = time.localtime(time.time())

print(tm.tm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_wday, tm.tm_yday, tm.tm_isdst)

 

3. 원하는 시간 포맷으로 변환

time.strftime('%Y-%m-%d %H:%M:%S ', time.localtime(time.time()))

 -> '2022-01-14 15:59:46 '

이때 ""에 표기하는 문자에 따라 다양하게 표현할 수 있습니다. 

 

나머지는 향후 추가

 

반응형

설정

트랙백

댓글

거래소에서 전달해주는 과거 데이터의 시간정보의 형태가 거래소마다 틀립니다. 암호화폐 거래소는 주로 UTC를 많이 사용하는데요. 처리의 용이하게 하기 위하여 UTC로 들어오는 시간데이터는 KST로 변환해서 전달해주는 것이 좋습니다.

 

upbit 거래소에서 과거 tick 데이터를 구하는 url은 아래와 같습니다.

api.upbit.com/v1/trades/ticks?market=KRW-BTC

 

여기에서 받은 데이터의 json 형태는 아래와 같습니다.

 

 

이 함수에서 돌려주는 json 값 중 날짜와 시간은 utc 값입니다. 다른 거래소와의 일관성을 유지하기 위하여 이것을 kst인 +9시간 뒤로 변경하여 처리하는 방법을 정리합니다.

 

문자열 형태의 일자 시간 정보를 datetime 형태로 변경하는 함수는 strptime()입니다. 입력 데이터의 format에 맞게 인자를 넣으면 됩니다.

 

dt_tm_utc = datetime.strptime(dt_tm,'%Y-%m-%d %H:%M:%S')

 

그후 utc와 kst 차이인 9시간을 +한 일자시간을 받기 위해서는 timedeta() 함수를 사용하면 됩니다.

 

tm_kst = dt_tm_utc + timedelta(hours=9)

 

이렇게 만들어진 datetime 값을 다시 문자열로 바꾸기 위해서는 strftime()함수를 사용하면 됩니다.

 

tm_kst_str = tm_kst.strftime('%Y-%m-%d %H:%M:%S')

 

tm_kst_str에는 날짜와 시간이 공백으로 구분된 문자열이 저장되어 있습니다. 여기에서 split() 함수를 사용하여 날짜와 시간을 분리하면 됩니다. 

 

from datetime import datetime, timedelta
trade_date_utc = 	"2020-12-26"
trade_time_utc =	"17:50:17"

# 일자 + 시간 문자열 만든다.
dt_tm = trade_date_utc + ' ' + trade_time_utc

# datetime 값으로 변환
dt_tm_utc = datetime.strptime(dt_tm,'%Y-%m-%d %H:%M:%S')

# +9 시간
tm_kst = dt_tm_utc + timedelta(hours=9)

# 일자 + 시간 문자열로 변환
tm_kst_str = tm_kst.strftime('%Y-%m-%d %H:%M:%S')

# 공백으로 일자/시간 나누기
tm = tm_kst_str.split(' ')

# kst 기준 날짜/시간을 구한다.
trade_date_kst = tm[0]
trade_time_utc = tm[1]
print(dt_tm_utc)
print(trade_date_kst, trade_time_utc)

print('')

 

 

그 결과는요..

 

 

변환이 잘 되었군요.

 

반응형

설정

트랙백

댓글

directory 만들고 지우기, 파일 이름 검색하기 등등 dir과 파일에 관련된 코딩이 필요할 때 glob와 os에 대하여 정리합니다.

 

우선 아래 두 패키지를 import 합니다.

 

import os
import glob

0. 현재 폴더 위치 얻기

   cwd = os.getcwd()

   윈도우와 리눅스를 구분하는 방법으로 \\가 있는지 확인하면 됩니다.

if "\\" in cwd :
    print('win')

 

1. 폴더(directory) 만들기

  원하는 이름의 dir를 만듭니다. 전략 실행하는 중에 매매와 상태에 대한 정보를 저장하여야합니다. 간단하게 파일을 사용할 수도 있고 DB를 사용할 수 있습니다. 우선 간단하게 파일을 사용합니다. 전략별로 혹은 일자별로 별도의 홀더를 만들어서 관리하면 좋을 것 같습니다. 따라서 필요한 이름으로 폴더를 만들 필요가 있습니다.

 폴더를 만드는 방법은 간단합니다. 

os.mkdir('.\\test')

2. 폴더(directory) 지우기

  일자가 지나면 기존 전략으로 생성한 폴더를 지워야하는 경우가 있습니다. 이를때는 rmdir를 사용합니다 단 rmdir()을 사용하기 전에 해당 폴더는 비워져있어야 합니다.

rmdir('.\\test')

 

3. 파일명 검색하기 

특정 폴더에 있는 파일명을 검색해봅시다. 프로그램이 비정상적으로 종료가 된 후 다시 시작할 때 기존 매매 상태로 복귀를 하여야 합니다. 이때 전략 실행 중 상태 값을 저장한 파일을 읽어서 이전과 같은 상태로 만들어야 합니다.

예를들어 .\\working 폴더에 아래와 같은 상태 정보가 저장되어 있다고 가정해봅시다.

우리가 해야할 일은 여기에 있는 파일 명을 list로 받아서 각 파일을 읽은 후 해당 ticker의 상태 값을 읽어야 합니다. 이때 사용할 함수는 glob.glob입니다. filter에 들어갈 적절한 문자열을 결정해서 전달하면 됩니다. 

def get_filenames() :
    files = []
    filter = '.\\working1\\' + '*_order_status.txt'
    for filename in glob.glob(filter): 
        files.append(filename)
    for fname in files :
        print (fname)
    return files

 

이 코드를 실행하면 아래과 같이 working에 있는 파일명 list를 받을 수 있습니다. 파일명에 있는 ticker 정보를 바탕으로 해당 ticker의 상태 정보를 update하면 됩니다.

 

4. 파일 지우기

 트레이딩이 끝나면 중간에 발생한 파일을 지워야 하는 경우가 있습니다. 특히 일 단위로 정산을 하는 경우에는 동작 중 발생한 파일을 반드시 지워야합니다.

3번에서 설명한 파일명 검색 후에 원하는 파일을 지우는 예제입니다. 아래 예제에서는 'BCH'를 가진 파일을 지웁니다.

 

    filter = '.\\working1\\' + '*_order_status.txt'
    for filename in glob.glob(filter): 
        if filename.find('BCH') >= 0 :
            os.remove(filename)

이 코드를 실행한 결과입니다. 'BCH'를 가진 파일만 지웠습니다.

 

 

반응형

설정

트랙백

댓글

자동매매프로그램을 돌리는 와중에 외출할 경우에는 신경이 많이 쓰입니다. 봇은 잘 동작하고 있는지 다른 큰 문제는 없는지 지 등등 자동매매 프로그램의 상태를 알고 싶죠. 이런 경우에 원격데스크탑 sw를 이용하여 pc에 접속할 수 있습니다만, 간단하게 휴대폰에서 자동매매 프로그램의 상태를 확인할 수 있으면 좋을 것 같습니다.

 

이번에 알아볼 내용은 텔레그램봇을 이용하여 xing api와 연동하는 부분입니다. 우선 텔레봇을 만들고 메세지를 주고 받는 방벙에 대하여 알아보겠습니다.

 

우선 텔레그램봇을 만드는 과정입니다.

일단 텔레그램을 휴대폰에 설치하신 후 아래와 같이 botfather를 찾은 후 선택을 합니다.

 

그 후 /newbot 을 입력한 후 봇을 설명하는 문구를 입력합니다.

 

다음으로는 봇의 이름을 입력합니다. 원하는 이름을 입력하시면 되는데, 만약 이미 등록된 봇과 같은 이름은 사용할 수 없습니다. 그러면 해당 이름의 봇이 사용할 token을 알려줍니다. 아래 빨간색으로 줄쳐진 부분이 XingTrBot의 ID라고 보시면 됩니다. 이 값을 프로그램에 사용하여야 합니다.

 

 

이제 나만의 telegram bot이 만들어졌습니다. telegram에서 찾아보죠.

앞에서 입력한 봇 이름을 검색하면 됩니다.

 

해당 봇을 선택한 후 /start를 누르면 봇이 동작상태가 됩니다.

 

이제 telegram 쪽에서 작업할 내용은 모두 끝났습니다. 파이썬 프로그램으로 bot과 대화하는 방법에 대하여 알아봅시다.

 

 

우선 telegram bot 파이썬 패키를 설치합니다.

 

pip install python-telegram-bot --upgrade

 

코드 상에서는 아래 패키지와 함수를 import하면 됩니다.

 

import telegram

from telegram.ext import Updater, MessageHandler, CommandHandler

 

그 후 my_token에 botFather가 준 token값을 복사합니다.

 

my_token = 'gotFather가 준 토큰'

 

동작방법은 간단합니다. '/'로 시작하는 경우에는 명령어로 구분합니다. '/'가 없으면 일반 메세지이고요.

 

명령어와 일반 메세지가 들어왔을 때 불리어지는 함수(handler)를 등록하면 끝입니다. 

 

우선 updater를 생성하고요.

 

updater = Updater(my_token)

 

작업을 하다보니 telegram_bot 버전이 upgrade되면서 사용방법이 많이 바뀌었습니다. 자세한 사항은 아래 참고하십시요.

https://github.com/python-telegram-bot/python-telegram-bot/wiki/Extensions-%E2%80%93-Your-first-Bot

 

python-telegram-bot/python-telegram-bot

We have made you a wrapper you can't refuse. Contribute to python-telegram-bot/python-telegram-bot development by creating an account on GitHub.

github.com

전체적인 사용법은 변화가 없는데, handler 함수가 불리어질 때 함수 인자가 변경이 되었습니다. 새 버전을 기준으로 설명합니다.

 

 

message가 왔을 때 받을 함수인 get_message, 명령어별로 받을 함수를 별도로 등록하면 됩니다.

아래 예에서 '/help'는 help_command()가 'sise'는 sise_command() 함수가 받습니다. 등록되지 않은 명령어의 경우에는 unknown() 함수 받도록 설정했습니다.

특히 sise의 경우에는 명령어 형식이 '/sise 코드' 이므로 코드값을 받을 수 있어야 합니다. 따라서 pass_args가 True로 설정하면 이 값도 받을 수 있습니다.

 

 

sise_command()를 좀 더 자세하게 보겠습니다.

함수의 인자는 아래와 같이 정의되어 있습니다.  사용자가 보낸 인자는 context.args 변수에 배열로 들어가있습니다. '/sise code' 로 입력을 하기 때문에 context.args[0]에 code가 들어있습니다. 과거 버전과 다르게 args가 context 안으로 들어갔습니다.

 

xing api와 연결하지 않아서 일단 임의의 값을 돌려주는 코드입니다. telegram bot이 어떻게 동작하는지 확인하는 용도이니 참고하십시요.

 

어떻게 동작하는지 telegram 화면으로 보여드리겠습니다.

 

 

의외로 telegram bot 만들고 메세지 주고 받는 방법이 간단합니다. 카카오톡에서도 이런 기능이 지원된다면 사용용처가 무척 많을 것 같은데요. 다음에는 xing api와 연동하여 시세 정보를 볼 수 있는 방법을 기술하도록 하겠습니다.

 

관련 소스는 아래 github에 올려놓았습니다.

 

https://github.com/multizone-quant/system-trading/blob/master/telegram-bot.py

 

multizone-quant/system-trading

logics for system trading. Contribute to multizone-quant/system-trading development by creating an account on GitHub.

github.com

 

반응형

설정

트랙백

댓글