-
비트코인 자동 매도,매수 프로그램 (coinone)IT 2021. 2. 4. 15:34
안녕하세요. 연휴동안 심심해서 만들어본
코인원 매도,매수 프로그램입니다.
주변에서 가상화폐 하시는분이 계셔서 한 100만원만 해볼까 해서 시작하다.
API문서가 잘되어있길래 한번 만들어보았어요 ㅎ
기본적인 로직은
1. 투자금액(시작) 에서 특정 ?% 오르면 매도
2. 특정 ?% 내리면 매수
입니다. 별거없어요 ㅎ
coinAnalyzer.py
#-*- coding: utf-8 -*-
입니다. 별거없어요 ㅎ
import websocket
import _thread
from threading import Thread, current_thread
import time
import json
import logging
import logging.handlers
import sys
import configparser
import math
import pprint
from decimal import Decimal
from coinOneBlance import CoinOneBlance
from coinOneMyLimitOrder import CoinOneMyLimitOrder
from coinOneLimitSell import CoinOneLimitSell
from coinOneLimitBuy import CoinOneLimitBuy
from coinOneCancel import CoinOneCancel
logger = logging.getLogger("coinAnalyzer")
logger.setLevel(logging.DEBUG)
file_max_bytes = 10 * 1024 * 1024
fileHandler = logging.handlers.RotatingFileHandler('./log/my.log', maxBytes=file_max_bytes, backupCount=10)
streamHandler = logging.StreamHandler()
formatter = logging.Formatter('[%(levelname)s|%(filename)s:%(lineno)s:%(threadName)s] %(asctime)s > %(message)s')
fileHandler.setFormatter(formatter)
streamHandler.setFormatter(formatter)
logger.addHandler(fileHandler)
logger.addHandler(streamHandler)
##config
CONFIG = None
SELL_PER = None #Decimal(0.03) #수익률 퍼센트 EARN_PER
BUY_PER = None #Decimal(0.03) #매도 퍼센트
KRW_SELL = None #Decimal(100000000) #팔때 KRW에 얼마더 추가할건지
KRW_BUY = None #Decimal(200000000) #살때 KRW에 얼마더 추가할건지
#WAIT
BUY_WAIT_SEC = None
SELL_WAIT_SEC = None
KRW_DEFEN = None #Decimal("0")
BTC_DEFEN = None #Decimal("0")
#config end
START_KRW_QUOTE = None
START_BTC_BALANCE = None
INIT_KRW_BALANCE = None
KRW_QUOTE = None
BTC_BALANCE = None
BUY_WAIT = False
SELL_WAIT = False
def on_message(ws, message):
try:
global START_KRW_QUOTE, START_BTC_BALANCE, INIT_KRW_BALANCE, KRW_QUOTE, BTC_BALANCE, SELL_WAIT, BUY_WAIT
websocketJson = json.loads(message)
if 'coinoneP' not in websocketJson:
logger.debug("webSocketJson not in coinoneP -> {}".format(websocketJson))
return
krwQuote = Decimal(json.loads(message)['coinoneP']) #1코인당 KRW
coinOneBalance = CoinOneBlance(CONFIG).get_result()
if "0"!=coinOneBalance['errorCode']:
logger.debug("coinOneBalance Error -> {}".format(coinOneBalance))
return
krwBalance = Decimal(coinOneBalance['krw']['balance'])
krwAvailBalance = Decimal(coinOneBalance['krw']['avail'])
btcBalance = Decimal(coinOneBalance['btc']['balance'])
btcAvailBalance = Decimal(coinOneBalance['btc']['avail'])
#btc 잔액이 변경 되면 다시 시작한다.
if START_BTC_BALANCE and BTC_BALANCE and START_BTC_BALANCE != BTC_BALANCE:
START_KRW_QUOTE = None
START_BTC_BALANCE = None
if not INIT_KRW_BALANCE:
INIT_KRW_BALANCE = krwBalance
if not START_KRW_QUOTE:
START_KRW_QUOTE = krwQuote
if not START_BTC_BALANCE:
START_BTC_BALANCE = btcBalance
if krwQuote!=KRW_QUOTE:
logger.debug("*** KRW Quote Modify \t start({}) -> this({}) = |{}| ***".format(START_KRW_QUOTE, krwQuote, krwQuote-START_KRW_QUOTE))
if btcBalance!=BTC_BALANCE:
logger.debug("*** btc balance Modify \t start({}) -> btcBal({}) btcAvailBal({}), krwBal({}) krwAvailBal = |{}| START_KRW_QUOTE({})***".format(START_BTC_BALANCE, btcBalance, btcAvailBalance , krwBalance, krwAvailBalance,btcBalance-START_BTC_BALANCE, START_KRW_QUOTE))
KRW_QUOTE = krwQuote
BTC_BALANCE = btcBalance
startKRW = Decimal(START_KRW_QUOTE * btcBalance) #시작금액
sellKRW = Decimal(startKRW + (startKRW * SELL_PER)) #판매 목적금액
buyKRW = Decimal(startKRW - (startKRW * BUY_PER)) #구매 목적금액
sellQuotKRW = Decimal(START_KRW_QUOTE + (START_KRW_QUOTE * SELL_PER)) #1btc당 krw 판매 목적금액
buyQuotKRW = Decimal(START_KRW_QUOTE - (START_KRW_QUOTE * BUY_PER)) #1btc당 krw 구매 목적금액
thisKRW = Decimal(KRW_QUOTE * btcBalance) #현재금액
startSellQuotePer = Decimal((krwQuote / sellQuotKRW) *100) #1btc당 krw 판매 목표금액 100%달성하기위한 현재 상태
startSellQuoteVal = Decimal(sellQuotKRW - krwQuote) #1btc당 krw 판매 목표금액 달성하기 위한 현재 부족한 금액상태
stateSellPer = Decimal((thisKRW / sellKRW) * 100) #판매 목표금액 100%달성하기위한 현재 상태
stateSellVal = Decimal(sellKRW - thisKRW) #판매 목표금액 달성하기 위한 현재 부족한 금액상태
startBuyQuotePer = Decimal((buyQuotKRW / krwQuote) *100) #1btc당 krw 판매 목표금액 100%달성하기위한 현재 상태
startBuyQuoteVal = Decimal(krwQuote - buyQuotKRW) #1btc당 krw 판매 목표금액 달성하기 위한 현재 부족한 금액상태
stateBuyPer = Decimal(((buyKRW / thisKRW) * 100)) #구매 목표금액 100%달성하기위한 현재 상태
stateBuyVal = Decimal(thisKRW - buyKRW) #구매 목표금액 달성하기 위한 현재 부족한 금액상태
stateStartThisVal = Decimal(thisKRW - startKRW) #시작 금액에서 얼마만큼 상하인지
stateStartThisQuoteVal = Decimal(krwQuote - START_KRW_QUOTE) #1btc당 krw 시작 금액에서 얼마만큼 상하인지
logger.debug("--SELL_WAIT:{} BUY_WAIT:{}, BTC:1btcKRWval({:10.8}) my:btcBal({:10.8} krwBal({}) btcKRWVal({:10.8}) initKRW({}) = {:10.8}"
.format(SELL_WAIT, BUY_WAIT, krwQuote, btcBalance, krwBalance, thisKRW, INIT_KRW_BALANCE, thisKRW - INIT_KRW_BALANCE));
logger.debug("SELL STATE: S({:10.8}) \t W({:10.8}%, {:10.8}) \t -> \t E({:10.8}) = UD({:10.8})"
.format(startKRW, stateSellPer, stateSellVal, sellKRW, stateStartThisVal))
logger.debug("SELL STATE: S({:10.8}) \t W({:10.8}%, {:10.8}) \t -> \t E({:10.8}) = UD({:10.8})"
.format(START_KRW_QUOTE, startSellQuotePer, startSellQuoteVal, sellQuotKRW, stateStartThisQuoteVal))
logger.debug(" BUY STATE: S({:10.8}) \t W({:10.8}%, {:10.8}) \t -> \t E({:10.8}) = UD({:10.8})"
.format(startKRW, stateBuyPer, stateBuyVal, buyKRW, stateStartThisVal))
logger.debug(" BUY STATE: S({:10.8}) \t W({:10.8}%, {:10.8}) \t -> \t E({:10.8}) = UD({:10.8})"
.format(START_KRW_QUOTE, startBuyQuotePer, startBuyQuoteVal, buyQuotKRW, stateStartThisQuoteVal))
#팔수있는 상황이면 팔아라
if not SELL_WAIT and startSellQuotePer > Decimal(100):
def run(*args):
global SELL_WAIT
SELL_WAIT = True
cancelSell()
time.sleep(1)
logger.debug("thread start {} {}".format("sell", current_thread().getName()))
try:
result = sell(btcBalance, krwQuote)
if result and '0'==result['errorCode']:
time.sleep(SELL_WAIT_SEC)
except Exception as e:
logger.debug(e)
finally:
try:
cancelSell()
except:
pass
SELL_WAIT = False
logger.debug("thread end {} {}".format("sell", current_thread().getName()))
Thread(target=run).start()
#살수 있는 상황이면 사라
if not BUY_WAIT and startBuyQuotePer > Decimal(100):
def run(*args):
global BUY_WAIT
BUY_WAIT = True
cancelBuy()
time.sleep(1)
logger.debug("thread start {} {}".format("buy", current_thread().getName()))
try:
result = buy(krwBalance, krwQuote)
if result and '0'==result['errorCode']:
time.sleep(BUY_WAIT_SEC)
except Exception as e:
logger.debug(e)
finally:
try:
cancelBuy()
except:
pass
BUY_WAIT = False
logger.debug("thread end {} {}".format("buy", current_thread().getName()))
Thread(target=run,).start()
except Exception as e:
logger.debug(e)
#매도
def sell(btcBalance, krwQuote):
global BTC_DEFEN
btcAvail = btcBalance - BTC_DEFEN
price = int(krwQuote + KRW_SELL)
logger.debug("==sell== btcBal({:10.8}) btcAvail[qty]({:10.8}), BTC_DEFFN({:10.8}), krwQuote({}), KRW_SELL({}) = price({})".format(btcBalance, btcAvail, BTC_DEFEN, krwQuote, KRW_SELL, price))
if(btcAvail < Decimal("0.0001")):
logger.debug("Sell no request Low")
return
payload = {
"price": price,
"qty": float(math.trunc(btcAvail*10000)/10000), #coinone은 소수점 4자리수까지만 받는다 최소단위 btc
"currency": "btc"
}
# log(sellPayload)
result = CoinOneLimitSell(CONFIG, payload).get_result()
logger.debug(result)
return result
#매수
def buy(krwBalance, krwQuote):
global KRW_DEFEN
krwAvail = krwBalance - KRW_DEFEN
qty = Decimal(krwAvail / krwQuote)
price = int(krwQuote + KRW_BUY)
logger.debug("==buy== qty {:10.8} kwrAvail({:10.8}) // krwBalance({:10.8}) KRW_DEFEN({:10.8}) krwQuote({:10.8}), KRW_BUY({}) = price({})".format(qty, krwAvail, krwBalance, KRW_DEFEN, krwQuote, KRW_BUY, price))
if(qty < Decimal("0.01")):
logger.debug("Buy no request Low")
return
payload = {
"price": price,
"qty": float(math.trunc(qty*10000)/10000), #coinone은 소수점 4자리수까지만 받는다 최소단위 btc
"currency": "btc"
}
result = CoinOneLimitBuy(CONFIG, payload).get_result()
logger.debug(result)
return result
def cancel(atOrder):
payload = {
"order_id": atOrder['orderId'],
"price": atOrder['price'],
"qty": atOrder['qty'],
"is_ask": 1 if 'ask'==atOrder['type'] else 0,
"currency": "btc"
}
logger.debug(CoinOneCancel(CONFIG, payload).get_result())
pass
def limitOrder():
limitOrderPayload = {
"currency": "btc"
}
limitOrder = CoinOneMyLimitOrder(CONFIG, limitOrderPayload).get_result();
return limitOrder
#ask
def cancelSell():
orders = limitOrder()
for it in orders['limitOrders']:
if('ask'==it['type']):
logger.debug("==cancelSell== {}".format(it))
cancel(it)
#bid
def cancelBuy():
# logger.debug("==cancelBuy==")
orders = limitOrder()
for it in orders['limitOrders']:
if('bid'==it['type']):
logger.debug("==cancelBuy== {}".format(it))
cancel(it)
def on_error(ws, error):
logger.debug(error)
def on_close(ws):
logger.debug("### closed ###")
def on_open(ws):
ws.send("{event: 'join', channel: 'live'}")
if __name__ == "__main__":
config = configparser.ConfigParser()
config.sections()
configFile = sys.argv[1]
configSection = sys.argv[2] if len(sys.argv)>=3 else "DEFAULT"
config.read(configFile)
config.sections()
""" config setting
[DEFAULT]
ACCESS_TOKEN = eee
SECRET_KEY = eee
SELL_PER = 0.03
BUY_PER = 0.03
KRW_SELL = 100000000
KRW_BUY = 200000000
"""
CONFIG = config[configSection]
SELL_PER = Decimal(CONFIG['SELL_PER'] if 'SELL_PER' in CONFIG else '0.3')
BUY_PER = Decimal(CONFIG['BUY_PER'] if 'BUY_PER' in CONFIG else '0.3')
KRW_BUY = Decimal(CONFIG['KRW_BUY'] if 'KRW_BUY' in CONFIG else '-500000')
KRW_SELL = Decimal(CONFIG['KRW_SELL'] if 'KRW_SELL' in CONFIG else '500000')
BUY_WAIT_SEC = Decimal(CONFIG['BUY_WAIT_SEC'] if 'BUY_WAIT_SEC' in CONFIG else '30')
SELL_WAIT_SEC = Decimal(CONFIG['SELL_WAIT_SEC'] if 'SELL_WAIT_SEC' in CONFIG else '30')
KRW_DEFEN = Decimal(CONFIG['KRW_DEFEN'] if 'KRW_DEFEN' in CONFIG else '0')
BTC_DEFEN = Decimal(CONFIG['BTC_DEFEN'] if 'BTC_DEFEN' in CONFIG else '0')
START_KRW_QUOTE = Decimal(CONFIG['START_KRW_QUOTE']) if 'START_KRW_QUOTE' in CONFIG else None
START_BTC_BALANCE = Decimal(CONFIG['START_BTC_BALANCE']) if 'START_BTC_BALANCE' in CONFIG else None
INIT_KRW_BALANCE = Decimal(CONFIG['INIT_KRW_BALANCE']) if 'INIT_KRW_BALANCE' in CONFIG else None
logger.debug("=====config=====")
logger.debug("SELL_PER : {}".format(SELL_PER))
logger.debug("BUY_PER : {}".format(BUY_PER))
logger.debug("KRW_SELL : {}".format(KRW_SELL))
logger.debug("KRW_BUY : {}".format(KRW_BUY))
logger.debug("BUY_WAIT_SEC : {}".format(BUY_WAIT_SEC))
logger.debug("SELL_WAIT_SEC : {}".format(SELL_WAIT_SEC))
logger.debug("KRW_DEFEN : {}".format(KRW_DEFEN))
logger.debug("BTC_DEFEN : {}".format(BTC_DEFEN))
logger.debug("START_KRW_QUOTE : {}".format(START_KRW_QUOTE))
logger.debug("START_BTC_BALANCE : {}".format(START_BTC_BALANCE))
logger.debug("INIT_KRW_BALANCE : {}".format(INIT_KRW_BALANCE))
websocket.enableTrace(True)
ws = websocket.WebSocketApp("wss://ws.coinone.co.kr:20013/",
on_message = on_message,
on_error = on_error,
on_close = on_close)
ws.on_open = on_open
ws.run_forever()coinOne.py
#-*- coding: utf-8 -*-
import base64
import simplejson as json
import hashlib
import hmac
import httplib2
import time
import pprint
import logging
from abc import *
logger = logging.getLogger("coinAnalyzer")
class CoinOne(metaclass=ABCMeta):
URL = 'https://api.coinone.co.kr/'
ACCESS_TOKEN = ''
SECRET_KEY = ''
def __init__(self, url, config):
self.URL = url
self.ACCESS_TOKEN = config['ACCESS_TOKEN']
self.SECRET_KEY = config['SECRET_KEY'].encode('utf-8')
@abstractclassmethod
def getPayLoad(self):
pass
def getFullPayLoad(self):
fullPayload = {}
fullPayload.update(self.getPayLoad())
fullPayload.update({
"access_token": self.ACCESS_TOKEN,
})
return fullPayload
def get_encoded_payload(self, payload):
payload[u'nonce'] = int(time.time()*1000)
dumped_json = json.dumps(payload)
encoded_json = base64.b64encode(dumped_json.encode('utf-8'))
return encoded_json
def get_signature(self, encoded_payload, secret_key):
signature = hmac.new(secret_key.upper(), encoded_payload, hashlib.sha512);
return signature.hexdigest()
def get_response(self, url, payload):
encoded_payload = self.get_encoded_payload(payload)
headers = {
'Content-type': 'application/json',
'X-COINONE-PAYLOAD': encoded_payload,
'X-COINONE-SIGNATURE': self.get_signature(encoded_payload, self.SECRET_KEY)
}
http = httplib2.Http()
response, content = http.request(self.URL, 'POST', headers=headers, body=encoded_payload)
return content
def get_result(self):
content = self.get_response(self.URL, self.getFullPayLoad())
content = json.loads(str(content.decode("utf-8")).replace('“','"').replace('”','"'))
return contentpython ./coinAnalyzer.py ./config.ini
config.ini
[DEFAULT] ACCESS_TOKEN = 7*******bb SECRET_KEY = 7********bb BUY_PER = 0.03 SELL_PER = 0.03 KRW_BUY = -5000 KRW_SELL = 5000 BUY_WAIT_SEC = 25 SELL_WAIT_SEC = 25 KRW_DEFEN = 1000000 BTC_DEFEN = 0.0001 #START_KRW_QUOTE = 5126000 #START_BTC_BALANCE = 0.2166830 INIT_KRW_BALANCE = 1000000
github
https://github.com/visualkhh/pro-CoinAnalyzer
'IT' 카테고리의 다른 글
java 자바 이미지 텍스트 변환하기 (0) 2021.02.05 하이버네이트 5.x 시작하기 (pdf) (0) 2021.02.04 groovy engine 사용시 memory out... (0) 2021.02.04 jenkins + sonarqube 연동 (0) 2021.02.04 jenkins + slack 연동 (0) 2021.02.04