728x90

<프로젝트 소개>


 

바이낸스 리더보드는 바이낸스 선물거래 유저들의 실시간 포지션과 수익률을 보여주는 사이트 입니다.

리더보드 사이트(https://www.binance.com/en/futures-activity/leaderboard/)

 

실제로 누적수익 250억 트레이더, 누적수익률이 15,000%인 트레이더 등 수많은 최상위 트레이더가 리더보드 사이트에

존재하며

 

이러한 사이트에서 자신이 따라하고싶은 트레이더를 선택하여 그 트레이더와 100% 똑같이 매수,매도가 자동으로 이루어지는 자동매매 프로그램을 개발하였습니다.

 

바이비트 API를 통해 거래가 이루어지기때문에 카피트레이딩 수수료가 전혀 존재하지 않으며 누구나 무료로 이용이 가능

합니다.

 

혼자서 진행한 개인프로젝트 이기때문에 UI/UX는 다소 유저친화적이지 않을수도 있지만 기능을 위주로 꾸준히 6달동안 개발하여 완성하였으며 테스팅도 완료하였습니다(유튜브 실시간 방송을 통해 테스트)

바이낸스 리더보드 사이트( https://www.binance.com/en/futures-activity/leaderboard/ )

 

<작동과정>


0. 바이비트 회원가입 및 API키를 발급받습니다 ( * 프로그램은 무료로 이용이 가능하나, 바이비트 제휴가입링크를 통해 가입하신분만 무료로 이용이 가능합니다.)

 

1. 바이낸스 리더보드 사이트에서 자신이 따라하고싶은 트레이더를 선택한 후 URL 주소를 프로그램에 입력합니다.

 

2. 레버리지, 운용자금 , 주문비율 등을 입력하고 카피트레이딩을 시작하면 끝입니다.

 

 

 

< 후기 > 


약 1만 달러로 CnTraderT  라는 트레이더를 카피트레이딩 한 결과 12월 약  8000달러의 수익이 발생했습니다.

CnTraderT 트레이더는 12월 93%의 수익률이 나왔지만 저는 약 85%의 수익률이 나왔습니다. 카피트레이딩 딜레이로 인해 조금(10~1분) 차이나는거 같습니다만 잘 작동하는듯 합니다. 

 

아무래도 최상위 트레이더같은 경우 추세매매를 하며 손절과 익절을 정확히 하기때문에 

카피트레이딩 할때  레버리지를 낮게 이용하면 안정적인 수익이 발생하는거 같습니다. 

 

 

 

 

 

< 프로그램 설치링크 & FAQ >


https://drive.google.com/file/d/1Q2K4JvtwzJZ1J-tSnaWE1sih1V-X-Z5O/view

 

build.zip

 

drive.google.com

 

dist 폴더 안에있는 exe파일을 실행하시면 됩니다.

 

 

프로그램은 바이비트 제휴가입링크를 통해 회원가입 하신 계정으로만 구동가능합니다. 

바이비트 제휴가입링크를 통해 가입하실경우 수수료 최대20%할인 + 증정금 지급이 되므로

기존에 계정이 있으신분들도 새로 가입하시는게 좋을듯합니다.

(https://partner.bybit.com/b/developer)

 

Buy & Sell Bitcoin, Ether | Cryptocurrency Exchange | Bybit

Crypto trading experience elevated. Buy, sell, trade BTC, altcoins & NFTs. Get access to the spot and futures market or stake your coins securely.

www.bybit.com

 

<이용문의 & 유튜브>


카카오톡 :  sososoll

유튜브 :  https://www.youtube.com/watch?v=VGaeYc-69rM 

 

728x90
728x90

단주 매매란?

 

주식 호가창을 보면 매수, 매도 체결 가격과 수량이 나타납니다. 호가창은 주식을 하는 사람이면 가장 쉽게 접할 수 있는 창인 만큼 속임수가 가득합니다. 그 중 단주매매는 호가창 매수1, 매도1 수량이 연속해서 계속 체결되는 것을 말합니다. 하기 그림의 예를 보시면 됩니다.

 

단주매매를 하는 이유?

 

실제 호가창에서 일어나는 단주매매의 체결 속도를 보시면 사람이 매수 주문을 넣고 바로 매도 주문을 넣고 이걸 반복해서 구현 할 수 있는 속도가 아닙니다. 즉 프로그램을 통해 매매를 하는 것입니다. 즉 세력들이 사용하는 매매입니다. 단주 매매가 일어나는 가격을 보면 매수는 한호가 위에서 매도는 한호가 아래에서 거래가 됩니다. 따라서 단주 매매가 발생하면 종목의 가격이 올랐다가 내렸다가 올랐다가 내렸다가를 반복하게 됩니다. 관심종목에 둔 사람들 눈에는 가격이 계속 변하는 것 처럼 보이게 되며 사람들의 이목을 끌게 됩니다. 이처럼 단주매매는 어떤 이유에서든 주가를 움직이는 세력이 사람들의 관심을 끌기 위해 사용합니다. 단주매매가 진행되는 호가창을 지켜보면 사람들의 반응과 세력의 행동을 볼 수 있습니다. 세력의 의도대로 곧 주가가 올라 갈 것 같으니 개미들이 사기 시작합니다.

 

실제로 아는분들은 단주매매를 쓰면서 몇천만원치를 매수해놓고 단주매매를 돌려 가격을 1~3%올린다음

빠르게 매도하여 빠진다고 합니다. 

 

주식에서는 단주매매시 경고1,2,3회 후 거래정지? 벌금으로 알고있는데 가상화폐 거래에서는 단주매매에 대한 제재하지 않습니다. 하지만 거래소쪽과 권장 통신(api주문)이 초당 8회 분당200회로 정해져있지만 딱히 아무런 제제를 당해본적이없어서 잘모르겠습니다.

 

가격은 15만원에 판매중입니다. jinsol0321 문의카톡

 

<작동영상 v1>

www.youtube.com/watch?v=6kr1p23H4uE

<작동영상 v2>

 

www.youtube.com/watch?v=FKlbRoaZgYU

 

 

 

 

 

<pyupbit 함수 정리>

 

pyupbit

Python Wrapper for Upbit API

Installation

파이썬 개발 환경으로 최신 버전의 Anaconda를 설치하세요. (Python3 버전용)

pip install pyupbit

pyjwt 모듈을 필요로 합니다. (pyjwt >= 2.0)

pip install pyjwt

Import

import pyupbit

Quotation API

  • Websocket은 초당 5회, 분당 100회 연결 요청할 수 있습니다.
  • 종목, 캔들, 체결, 티커, 호가 API는 분당 600회, 초당 10회 사용 가능합니다.

암호화폐 목록

get_tickers 함수는 업비트가 지원하는 모든 암호화폐 목록을 얻어옵니다.

print(pyupbit.get_tickers())
['KRW-BTC', 'KRW-DASH', 'KRW-ETH', 'BTC-NEO', 'BTC-ETH', 'BTC-LTC', ... ]

업비트가 지원하는 암호화폐 목록 중 특정 시장(fiat)에 매매가 가능한 목록만 얻어올 수 있습니다. KRW/BTC/USDT 시장을 조회할 수 있습니다.

print(pyupbit.get_tickers(fiat="KRW"))
['KRW-BTC', 'KRW-DASH', 'KRW-ETH', 'KRW-NEO', 'KRW-MTL', 'KRW-LTC', ...]

최근 체결가격

get_current_price 함수는 암호화폐의 현재가를 얻어옵니다. 함수로 티커를 넣어줘야 합니다.

print(pyupbit.get_current_price("KRW-BTC"))

float 타입의 현재가가 반환됩니다.

8392000.0

리스트에 여러 개의 티커를 입력해 한 번에 현재가를 조회할 수 있습니다.

print(pyupbit.get_current_price(["KRW-BTC", "KRW-XRP"]))

여러 종목을 조회한 경우 딕셔너리로 현재가를 리턴합니다.

{'KRW-BTC': 8300000.0, 'KRW-XRP': 511.0}

get_current_price 함수는 최대 100개의 암호화폐를 조회할 수 있습니다. 100개 이상일 경우 분할해서 반복 조회해야 합니다.

차트 데이터

get_ohlcv 함수는 고가/시가/저가/종가/거래량을 DataFrame으로 반환합니다.

df = pyupbit.get_ohlcv("KRW-BTC")
print(df.tail())

날짜가 오름차순으로 정렬돼 최근 날짜가 마지막에 위치합니다.

2021-03-21 09:00:00  67849000.0  68715000.0  65451000.0  67120000.0   8097.428878
2021-03-22 09:00:00  67064000.0  68380000.0  64345000.0  64725000.0   8366.410551
2021-03-23 09:00:00  64728000.0  66279000.0  63000000.0  65458000.0   9961.040596
2021-03-24 09:00:00  65458000.0  68370000.0  64500000.0  64777000.0  11366.404524
2021-03-25 09:00:00  64777000.0  65305000.0  63319000.0  64257000.0   2770.703203

count 파라미터는 조회 갯수를 지정합니다. 최근 영업일 부터 이전 count만큼의 이전 영업일까지 조회합니다. count 파라미터를 입력하지 않을 경우 default value는 200입니다.

df = pyupbit.get_ohlcv("KRW-BTC", count=5)
print(len(df))

위 코드는 최근 영업일 부터 과거 5개의 데이터가 조회됩니다.

5

interval 파라미터는 조회단위를 지정합니다. 파라미터에는 다음 값을 지정할 수 있습니다.

  • day/minute1/minute3/minute5/minute10/minute15/minute30/minute60/minute240/week/month
print(pyupbit.get_ohlcv("KRW-BTC", interval="day")              # 일봉 데이터 (5일)
print(pyupbit.get_ohlcv("KRW-BTC", interval="minute1"))         # 분봉 데이터
print(pyupbit.get_ohlcv("KRW-BTC", interval="week"))            # 주봉 데이터

to 파라미터에 입력된 이전 단위(interval)까지의 데이터를 데이터프레임으로 얻을 수 있습니다. 예를 들어, 다음 코드는 2020-10-10일 보다 하루 전인 2020-10-09을 까지의 200개 데이터를 조회합니다. 단위를 설정하지 않았으니 단위는 일봉입니다.

print(pyupbit.get_ohlcv("KRW-BTC", to="20201010"))

intervalminute1로 지정한 경우 2020-10-10 보다 1분 이전 (2020-10-09 23:59:00)까지의 200개 데이터를 반환합니다.

print(pyupbit.get_ohlcv("KRW-BTC", interval="minute1", to="20201010"))

기준 시간 단위로 shift된 일봉을 계산할 수도 있습니다.

예) 2019-06-01 12:00:00 ~ 2019-06-02 11:59:59

print(pyupbit.get_daily_ohlcv_from_base("KRW-BTC", base=12))

예) 2019-06-01 13:00:00 ~ 2019-06-02 12:59:59

print(pyupbit.get_daily_ohlcv_from_base("KRW-BTC", base=13))

매수/매도 호가

get_orderbook 함수는 매수/매도 호가 정보를 조회합니다.

print(pyupbit.get_orderbook(tickers="KRW-BTC"))

리스트 안에 딕셔너리로 호가정보가 들어있습니다.

  • market : 암호화폐 티커
  • timestamp : 조회시간 (단위 ms)
  • orderbook_units : 매도호가/매수호가 정보
[{'market': 'KRW-BTC', 'timestamp': 1532118943687, 'total_ask_size': 17.08116346, 'total_bid_size': 3.07150192, 'orderbook_units': [{'ask_price': 8390000.0, 'bid_price': 8389000.0, 'ask_size': 3.16057415, 'bid_size': 0.5515136}, {'ask_price': 8392000.0, 'bid_price': 8387000.0, 'ask_size': 0.71247596, 'bid_size': 0.95157819}, {'ask_price': 8393000.0, 'bid_price': 8386000.0, 'ask_size': 3.70536818, 'bid_size': 0.15824907}, {'ask_price': 8398000.0, 'bid_price': 8385000.0, 'ask_size': 0.00481809, 'bid_size': 0.00119147}, {'ask_price': 8399000.0, 'bid_price': 8383000.0, 'ask_size': 1.1228337, 'bid_size': 0.05}, {'ask_price': 8400000.0, 'bid_price': 8380000.0, 'ask_size': 0.48354827, 'bid_size': 0.00613734}, {'ask_price': 8401000.0, 'bid_price': 8375000.0, 'ask_size': 0.00433629, 'bid_size': 0.05}, {'ask_price': 8402000.0, 'bid_price': 8374000.0, 'ask_size': 2.7434153, 'bid_size': 0.32104953}, {'ask_price': 8420000.0, 'bid_price': 8373000.0, 'ask_size': 0.0028, 'bid_size': 0.5010063}, {'ask_price': 8428000.0, 'bid_price': 8370000.0, 'ask_size': 5.14099352, 'bid_size': 0.48077642}]}]

tickers 파라미터에 리스트로 티커를 넣으면, 한 번에 여러 종목의 호가를 조회할 수 있습니다.

print(pyupbit.get_orderbook(tickers=["KRW-BTC", "KRW-XRP"]))

Exchange API

주문은 초당 8회, 분당 200회 / 주문 외 요청은 초당 30회, 분당 900회 사용 가능합니다.

로그인

Access Key와 Sercret Key를 사용해서 Upbit 객체를 생성합니다. 이는 웹페이지에서 로그인하는 것과 같습니다.

access = "73kVqowGQOGEjdR31221j31j2ifekjkgjekgjekg"          # 본인 값으로 변경
secret = "egjekgj3iekeEEkej3i3j3iejjwiEejiejeEeijg"          # 본인 값으로 변경
upbit = Upbit(access, secret)

잔고 조회

get_balance 메서드는 입력받은 티커의 보유 수량 정보를 조회합니다.

print(upbit.get_balance("KRW-XRP"))     # KRW-XRP 조회
print(upbit.get_balance("KRW"))         # 보유 현금 조회

get_balances 메서드는 보유 중인 모든 암호화폐의 잔고 및 단가 정보를 딕셔너리로 조회합니다.

print(upbit.get_balances())
[{'currency': 'KRW',
  'balance': '0.34689181',
  'locked': '0.0',
  'avg_buy_price': '0',
  'avg_buy_price_modified': True,
  'unit_currency': 'KRW'},
 {'currency': 'BTC',
  'balance': '0.00174304',
  'locked': '0.0',
  'avg_buy_price': '64387000',
  'avg_buy_price_modified': False,
  'unit_currency': 'KRW'},]

지정가 매수/매도 주문

지정한 가격에 주문을 요청합니다. 다음은 원화 시장에 리플을 600원에 20개 매도 합니다.

# 매도
print(upbit.sell_limit_order("KRW-XRP", 600, 20))

주문 정보가 딕셔너리로 반환됩니다. uuid는 주문에 대한 고윳값으로 이를 사용해 추후 주문을 취소하거나 정정할 수 있습니다.

{'uuid': '0bcf0916-a7f5-49ed-80a9-a45e9e190cd3',
 'side': 'ask',
 'ord_type': 'limit',
 'price': '600.0',
 'state': 'wait',
 'market': 'KRW-XRP',
 'created_at': '2021-03-21T15:24:11+09:00',
 'volume': '20.0',
 'remaining_volume': '20.0',
 'reserved_fee': '0.0',
 'remaining_fee': '0.0',
 'paid_fee': '0.0',
 'locked': '20.0',
 'executed_volume': '0.0',
 'trades_count': 0}

다음은 원화 시장에 리플을 613원에 10개 매수 합니다.

# 매수
print(upbit.buy_limit_order("KRW-XRP", 613, 10))
{'uuid': '1907dcdc-2b96-4d85-9963-866f7aa220cd',
 'side': 'bid',
 'ord_type': 'limit',
 'price': '613.0',
 'state': 'wait',
 'market': 'KRW-XRP',
 'created_at': '2021-03-21T15:10:32+09:00',
 'volume': '10.0',
 'remaining_volume': '10.0',
 'reserved_fee': '3.065',
 'remaining_fee': '3.065',
 'paid_fee': '0.0',
 'locked': '6133.065',
 'executed_volume': '0.0',
 'trades_count': 0}

시장가 매수/매도 주문

시장가 매수는 매우선 매도호가에 즉시 매수합니다. buy_market_order 메서드로 티커와 매수 금액만을 입력합니다. 매수 금액은 수수료를 포함한 금액입니다. 다음 예제에서 주문한 10000원은 수수료가 포함된 금액입니다. 수수료가 0.05%라면 수수료를 제외한 9995원만이 주문에 사용됩니다.

print(upbit.buy_market_order("KRW-XRP", 10000))

다음은 리플 30개를 시장가 매도합니다. 매도대금이 총 10000원이라면 수수료를 제외한 금액이 입금됩니다. 만약 수수료가 0.05%라면 9995원 받을 수 있습니다.

print(upbit.sell_market_order("KRW-XRP", 30))

미체결 주문 조회

get_order 메서드는 입력된 암호화폐의 미체결 주문을 조회합니다.

upbit.get_order("KRW-LTC")

미체결 주문이 있다면 리스트로 상세 내역을 반환합니다. 다음은 250000원에 매도(ask) 주문한 LTC이 1개(volume)있다는 의미입니다.

[{'uuid': '50e184b3-9b4f-4bb0-9c03-30318e3ff10a',
  'side': 'ask',
  'ord_type': 'limit',
  'price': '250000.0',
  'state': 'wait',
  'market': 'KRW-LTC',
  'created_at': '2021-03-25T14:10:53+09:00',
  'volume': '1.0',
  'remaining_volume': '1.0',
  'reserved_fee': '0.0',
  'remaining_fee': '0.0',
  'paid_fee': '0.0',
  'locked': '1.0',
  'executed_volume': '0.0',
  'trades_count': 0}]

state 파라미터를 사용하면 완료된 주문을 조회할 수 있습니다.

print(upbit.get_order("KRW-LTC", state="done"))
[{'uuid': '0694def7-5ada-405f-b0f3-053801d5b190',
  'side': 'ask',
  'ord_type': 'market',
  'price': None,
  'state': 'done',
  'market': 'KRW-LTC',
  'created_at': '2021-03-21T14:43:40+09:00',
  'volume': '0.07336815',
  'remaining_volume': '0.0',
  'reserved_fee': '0.0',
  'remaining_fee': '0.0',
  'paid_fee': '8.39331636',
  'locked': '0.0',
  'executed_volume': '0.07336815',
  'trades_count': 1},
 {'uuid': '48d6d451-3db5-4357-9d5a-bfb8f417c943',
  'side': 'ask',
  'ord_type': 'limit',
  'price': '230000.0',
  'state': 'done',
  'market': 'KRW-LTC',
  'created_at': '2021-03-17T01:06:55+09:00',
  'volume': '0.5',
  'remaining_volume': '0.0',
  'reserved_fee': '0.0',
  'remaining_fee': '0.0',
  'paid_fee': '58.775',
  'locked': '0.0',
  'executed_volume': '0.5',
  'trades_count': 2}]

매수/매도 주문 취소

주문 함수의 리턴 값 중 uuid 값을 사용해서 주문을 취소할 수 있습니다.

print(upbit.cancel_order('50e184b3-9b4f-4bb0-9c03-30318e3ff10a'))

정상 처리됐다면 다음과 같이 딕셔너리가 반환됩니다.

{'uuid': '50e184b3-9b4f-4bb0-9c03-30318e3ff10a', 'side': 'ask', 'ord_type': 'limit', 'price': '250000.0', 'state': 'wait', 'market': 'KRW-LTC', 'created_at': '2021-03-25T14:10:53+09:00', 'volume': '1.0', 'remaining_volume': '1.0', 'reserved_fee': '0.0', 'remaining_fee': '0.0', 'paid_fee': '0.0', 'locked': '1.0', 'executed_volume': '0.0', 'trades_count': 0}

웹소켓

WebSocket을 이용해서 현재가, 호가, 체결에 대한 정보를 수신합니다.

  • 첫 번째 파라미터에는 수신정보를 입력하며 ticker, orderbook, transaction을 사용할 수 있습니다.
  • 두 번째 파라미터는 구독할 필터를 설정하며 암호화폐의 티커를 입력합니다. 현재 버전에서는 원화 시장만을 지원합니다.
from pyupbit import WebSocketManager

if __name__ == "__main__":
    wm = WebSocketManager("ticker", ["KRW-BTC"])
    for i in range(10):
        data = wm.get()
        print(data)
    wm.terminate()

주의: 웹소켓의 multiprocessing을 위해 __name__ guard를 반드시 써줘야 합니다.

PyQt5와 함께 웹소켓을 사용하는 예제는 다음 코드를 참고하세요.

  • 버튼을 클릭하면 웹소켓에서 가격정보를 가져와서 화면에 출력합니다.

 

 

<함수 자세히 보기 >

 

 

 

def get_tick_size(price):
    if price >= 2000000:
        tick_size = round(price / 1000) * 1000
    elif price >= 1000000:
        tick_size = round(price / 500) * 500
    elif price >= 500000:
        tick_size = round(price / 100) * 100
    elif price >= 100000:
        tick_size = round(price / 50) * 50
    elif price >= 10000:
        tick_size = round(price / 10) * 10
    elif price >= 1000:
        tick_size = round(price / 5) * 5
    elif price >= 100:
        tick_size = round(price / 1) * 1
    elif price >= 10:
        tick_size = round(price / 0.1) * 0.1
    else:
        tick_size = round(price / 0.01) * 0.01
    return tick_size


class Upbit:
    def __init__(self, access, secret):
        self.access = access
        self.secret = secret

    def _request_headers(self, query=None):
        payload = {
            "access_key": self.access,
            "nonce": str(uuid.uuid4())
        }

        if query is not None:
            m = hashlib.sha512()
            m.update(urlencode(query).encode())
            query_hash = m.hexdigest()
            payload['query_hash'] = query_hash
            payload['query_hash_alg'] = "SHA512"

        #jwt_token = jwt.encode(payload, self.secret, algorithm="HS256").decode('utf-8')
        jwt_token = jwt.encode(payload, self.secret, algorithm="HS256")     # PyJWT >= 2.0
        authorization_token = 'Bearer {}'.format(jwt_token)
        headers = {"Authorization": authorization_token}
        return headers

    # region balance
    def get_balances(self, contain_req=False):
        """
        전체 계좌 조회
        :param contain_req: Remaining-Req 포함여부
        :return: 내가 보유한 자산 리스트
        [contain_req == True 일 경우 Remaining-Req가 포함]
        """
        try:
            url = "https://api.upbit.com/v1/accounts"
            headers = self._request_headers()
            result = _send_get_request(url, headers=headers)
            if contain_req:
                return result
            else:
                return result[0]
        except Exception as x:
            print(x.__class__.__name__)
            return None

    def get_balance(self, ticker="KRW", contain_req=False):
        """
        특정 코인/원화의 잔고를 조회하는 메소드
        :param ticker: 화폐를 의미하는 영문 대문자 코드
        :param contain_req: Remaining-Req 포함여부
        :return: 주문가능 금액/수량 (주문 중 묶여있는 금액/수량 제외)
        [contain_req == True 일 경우 Remaining-Req가 포함]
        """
        try:
            # fiat-ticker
            # KRW-BTC
            if '-' in ticker:
                ticker = ticker.split('-')[1]

            balances, req = self.get_balances(contain_req=True)

            # search the current currency
            balance = 0
            for x in balances:
                if x['currency'] == ticker:
                    balance = float(x['balance'])
                    break

            if contain_req:
                return balance, req
            else:
                return balance
        except Exception as x:
            print(x.__class__.__name__)
            return None

    def get_balance_t(self, ticker='KRW', contain_req=False):
        """
        특정 코인/원화의 잔고 조회(balance + locked)
        :param ticker: 화폐를 의미하는 영문 대문자 코드
        :param contain_req: Remaining-Req 포함여부
        :return: 주문가능 금액/수량 (주문 중 묶여있는 금액/수량 포함)
        [contain_req == True 일 경우 Remaining-Req가 포함]
        """
        try:
            # KRW-BTC
            if '-' in ticker:
                ticker = ticker.split('-')[1]

            balances, req = self.get_balances(contain_req=True)

            balance = 0
            locked = 0
            for x in balances:
                if x['currency'] == ticker:
                    balance = float(x['balance'])
                    locked = float(x['locked'])
                    break

            if contain_req:
                return balance + locked, req
            else:
                return balance + locked
        except Exception as x:
            print(x.__class__.__name__)
            return None

    def get_avg_buy_price(self, ticker='KRW', contain_req=False):
        """
        특정 코인/원화의 매수평균가 조회
        :param ticker: 화폐를 의미하는 영문 대문자 코드
        :param contain_req: Remaining-Req 포함여부
        :return: 매수평균가
        [contain_req == True 일 경우 Remaining-Req가 포함]
        """
        try:
            # KRW-BTC
            if '-' in ticker:
                ticker = ticker.split('-')[1]

            balances, req = self.get_balances(contain_req=True)

            avg_buy_price = 0
            for x in balances:
                if x['currency'] == ticker:
                    avg_buy_price = float(x['avg_buy_price'])
                    break
            if contain_req:
                return avg_buy_price, req
            else:
                return avg_buy_price

        except Exception as x:
            print(x.__class__.__name__)
            return None

    def get_amount(self, ticker, contain_req=False):
        """
        특정 코인/원화의 매수금액 조회
        :param ticker: 화폐를 의미하는 영문 대문자 코드 (ALL 입력시 총 매수금액 조회)
        :param contain_req: Remaining-Req 포함여부
        :return: 매수금액
        [contain_req == True 일 경우 Remaining-Req가 포함]
        """
        try:
            # KRW-BTC
            if '-' in ticker:
                ticker = ticker.split('-')[1]

            balances, req = self.get_balances(contain_req=True)

            amount = 0
            for x in balances:
                if x['currency'] == 'KRW':
                    continue

                avg_buy_price = float(x['avg_buy_price'])
                balance = float(x['balance'])
                locked = float(x['locked'])

                if ticker == 'ALL':
                    amount += avg_buy_price * (balance + locked)
                elif x['currency'] == ticker:
                    amount = avg_buy_price * (balance + locked)
                    break
            if contain_req:
                return amount, req
            else:
                return amount
        except Exception as x:
            print(x.__class__.__name__)
            return None

    # endregion balance

    # region chance
    def get_chance(self, ticker, contain_req=False):
        """
        마켓별 주문 가능 정보를 확인.
        :param ticker:
        :param contain_req: Remaining-Req 포함여부
        :return: 마켓별 주문 가능 정보를 확인
        [contain_req == True 일 경우 Remaining-Req가 포함]
        """
        try:
            url = "https://api.upbit.com/v1/orders/chance"
            data = {"market": ticker}
            headers = self._request_headers(data)
            result = _send_get_request(url, headers=headers, data=data)
            if contain_req:
                return result
            else:
                return result[0]
        except Exception as x:
            print(x.__class__.__name__)
            return None

    # endregion chance

    # region order
    def buy_limit_order(self, ticker, price, volume, contain_req=False):
        """
        지정가 매수
        :param ticker: 마켓 티커
        :param price: 주문 가격
        :param volume: 주문 수량
        :param contain_req: Remaining-Req 포함여부
        :return:
        """
        try:
            url = "https://api.upbit.com/v1/orders"
            data = {"market": ticker,
                    "side": "bid",
                    "volume": str(volume),
                    "price": str(price),
                    "ord_type": "limit"}
            headers = self._request_headers(data)
            result = _send_post_request(url, headers=headers, data=data)
            if contain_req:
                return result
            else:
                return result[0]
        except Exception as x:
            print(x.__class__.__name__)
            return None

    def buy_market_order(self, ticker, price, contain_req=False):
        """
        시장가 매수
        :param ticker: ticker for cryptocurrency
        :param price: KRW
        :param contain_req: Remaining-Req 포함여부
        :return:
        """
        try:
            url = "https://api.upbit.com/v1/orders"
            data = {"market": ticker,  # market ID
                    "side": "bid",  # buy
                    "price": str(price),
                    "ord_type": "price"}
            headers = self._request_headers(data)
            result = _send_post_request(url, headers=headers, data=data)
            if contain_req:
                return result
            else:
                return result[0]
        except Exception as x:
            print(x.__class__.__name__)
            return None

    def sell_market_order(self, ticker, volume, contain_req=False):
        """
        시장가 매도 메서드
        :param ticker: 가상화폐 티커
        :param volume: 수량
        :param contain_req: Remaining-Req 포함여부
        :return:
        """
        try:
            url = "https://api.upbit.com/v1/orders"
            data = {"market": ticker,  # ticker
                    "side": "ask",  # sell
                    "volume": str(volume),
                    "ord_type": "market"}
            headers = self._request_headers(data)
            result = _send_post_request(url, headers=headers, data=data)
            if contain_req:
                return result
            else:
                return result[0]
        except Exception as x:
            print(x.__class__.__name__)
            return None

    def sell_limit_order(self, ticker, price, volume, contain_req=False):
        """
        지정가 매도
        :param ticker: 마켓 티커
        :param price: 주문 가격
        :param volume: 주문 수량
        :param contain_req: Remaining-Req 포함여부
        :return:
        """
        try:
            url = "https://api.upbit.com/v1/orders"
            data = {"market": ticker,
                    "side": "ask",
                    "volume": str(volume),
                    "price": str(price),
                    "ord_type": "limit"}
            headers = self._request_headers(data)
            result = _send_post_request(url, headers=headers, data=data)
            if contain_req:
                return result
            else:
                return result[0]
        except Exception as x:
            print(x.__class__.__name__)
            return None

    def cancel_order(self, uuid, contain_req=False):
        """
        주문 취소
        :param uuid: 주문 함수의 리턴 값중 uuid
        :param contain_req: Remaining-Req 포함여부
        :return:
        """
        try:
            url = "https://api.upbit.com/v1/order"
            data = {"uuid": uuid}
            headers = self._request_headers(data)
            result = _send_delete_request(url, headers=headers, data=data)
            if contain_req:
                return result
            else:
                return result[0]
        except Exception as x:
            print(x.__class__.__name__)
            return None

    def get_order(self, ticker, state='wait', kind='normal', contain_req=False):
        """
        주문 리스트 조회
        :param ticker: market
        :param state: 주문 상태(wait, done, cancel)
        :param kind: 주문 유형(normal, watch)
        :param contain_req: Remaining-Req 포함여부
        :return:
        """
        # TODO : states, uuids, identifiers 관련 기능 추가 필요
        try:
            url = "https://api.upbit.com/v1/orders"
            data = {'market': ticker,
                    'state': state,
                    'kind': kind,
                    'order_by': 'desc'
                    }
            headers = self._request_headers(data)
            result = _send_get_request(url, headers=headers, data=data)
            if contain_req:
                return result
            else:
                return result[0]
        except Exception as x:
            print(x.__class__.__name__)
            return None
    # endregion order

    def get_individual_order(self, uuid, contain_req=False):
        """
        주문 리스트 조회
        :param uuid: 주문 id
        :param contain_req: Remaining-Req 포함여부
        :return:
        """
        # TODO : states, uuids, identifiers 관련 기능 추가 필요
        try:
            url = "https://api.upbit.com/v1/order"
            data = {'uuid': uuid}
            headers = self._request_headers(data)
            result = _send_get_request(url, headers=headers, data=data)
            if contain_req:
                return result
            else:
                return result[0]
        except Exception as x:
            print(x.__class__.__name__)
            return None
    # endregion order

    def withdraw_coin(self, currency, amount, address, secondary_address='None', transaction_type='default', contain_req=False):
        """
        코인 출금
        :param currency: Currency symbol
        :param amount: 주문 가격
        :param address: 출금 지갑 주소
        :param secondary_address: 2차 출금주소 (필요한 코인에 한해서)
        :param transaction_type: 출금 유형
        :param contain_req: Remaining-Req 포함여부
        :return:
        """
        try:
            url = "https://api.upbit.com/v1/withdraws/coin"
            data = {"currency": currency,
                    "amount": amount,
                    "address": address,
                    "secondary_address": secondary_address,
                    "transaction_type": transaction_type}
            headers = self._request_headers(data)
            result = _send_post_request(url, headers=headers, data=data)
            if contain_req:
                return result
            else:
                return result[0]
        except Exception as x:
            print(x.__class__.__name__)
            return None
    
    def withdraw_cash(self, amount: str, contain_req=False):
        """
        현금 출금
        :param amount: 출금 액수
        :param contain_req: Remaining-Req 포함여부
        :return:
        """
        try:
            url = "https://api.upbit.com/v1/withdraws/krw"
            data = {"amount": amount}
            headers = self._request_headers(data)
            result = _send_post_request(url, headers=headers, data=data)
            if contain_req:
                return result
            else:
                return result[0]
        except Exception as x:
            print(x.__class__.__name__)
            return None
    
    def get_individual_withdraw_order(self, uuid: str, currency: str, contain_req=False):
        """
        현금 출금
        :param uuid: 출금 UUID
        :param txid: 출금 TXID
        :param currency: Currency 코드
        :param contain_req: Remaining-Req 포함여부
        :return:
        """
        try:
            url = "https://api.upbit.com/v1/withdraw"
            data = {"uuid": uuid, "currency": currency}
            headers = self._request_headers(data)
            result = _send_get_request(url, headers=headers, data=data)
            if contain_req:
                return result
            else:
                return result[0]
        except Exception as x:
            print(x.__class__.__name__)
            return None


if __name__ == "__main__":
    import pprint
    with open("../upbit.txt") as f:
        lines = f.readlines()
        access = lines[0].strip()
        secret = lines[1].strip()

    # Exchange API 사용을 위한 객체 생성
    upbit = Upbit(access, secret)

    #-------------------------------------------------------------------------
    # Exchange API
    #-------------------------------------------------------------------------
    # 자산 - 전체 계좌 조회
    balances = upbit.get_balances()
    pprint.pprint(balances)

    # 원화 잔고 조회
    print(upbit.get_balance(ticker="KRW"))          # 보유 KRW
    print(upbit.get_amount('ALL'))                  # 총매수금액
    print(upbit.get_balance(ticker="KRW-BTC"))      # 비트코인 보유수량
    print(upbit.get_balance(ticker="KRW-XRP"))      # 리플 보유수량

    #print(upbit.get_chance('KRW-HBAR'))
    #print(upbit.get_order('KRW-BTC'))

    # 매도
    # print(upbit.sell_limit_order("KRW-XRP", 1000, 20))

    # 매수
    # print(upbit.buy_limit_order("KRW-XRP", 200, 20))

    # 주문 취소
    # print(upbit.cancel_order('82e211da-21f6-4355-9d76-83e7248e2c0c'))

    # 시장가 주문 테스트
    # upbit.buy_market_order("KRW-XRP", 10000)

    # 시장가 매도 테스트
    # upbit.sell_market_order("KRW-XRP", 36)

 

728x90
728x90

해당글은 외주를 받아 제작하게 되었습니다.  카톡jinsol0321 

 

주식에서는 순간체결량(키움증권 [0148])이라는 기능을 HTS에서 제공합니다.

 

순간체결량은 순간적으로 한 종목에 집중되거나 한번에 대규모 주문이 실행될 경우 해당 종목의 체결량이 순간적으로 늘어나게 되는데, 이러한 대규모 주문이 집중되는 경우는 순간펌핑,설거지 , 공시 등 다양한 이유가 존재합니다.

이러한 순간적인 높은 체결량을 사람눈으로 120개 가까이되는 코인들을 전부 체크하기란 불가능에 가깝습니다.

 

개발하고자 하는 프로그램은 가상화폐거래소 Upbit에서 KRW마켓에 모든코인 117개를 매초마다 최근 1분봉 OR 3분봉 파싱하여(거래량,가격)

 

순간체결금액이 사용자가 설정한금액보다 높은값의 거래량이 터졌을때 알람이 가도록 하는 프로그램을 개발하는게

 

목표입니다. 

 

ex) 사용자의 설정값이 1분봉 50억이라고 설정햇을때 펀디엑스에서 최근 1분봉 거래량이 50억을 넘었을때 프로그램에서 알람이 울리며, 텔레그램으로도 알람이 가도록 프로그램이 작동합니다. 

 

 

개발과정에서 순간체결량이 조건을 달성했을때 친숙한 sound를 재생하게 하려했지만, UTF-8 오류로 인해 그냥 

winsound에서 100헤르츠 소리를 나도록설정하였습니다.(오래듣기 싫은소리)

 

사용라이브러리

 

 

해당 프로그램을 실행하기위해서는 python3.7.9버전과 해당 라이브러리들을 설치해야 실행됩니다.

 

1분봉 감시

www.youtube.com/watch?v=Cv4z3EeyaAY

 

 

3분봉 감시

www.youtube.com/watch?v=fuIXqPKW1vk

 

728x90
728x90

ititit1.tistory.com/37

 

판매) 업비트 호가 흔들기 프로그램 / 업비트 단주매매 프로그램 판매 2021-03-24

2021-02-19 업비트api변경, 최소주문액변경 등 옛날 단주프로그램으로 실행되지않습니다. 업비트 단주매매 프로그램 판매중 문의 jinsol0321 카톡 1.1 준비과정 (업비트 Open key 발급) 우선 업비트 계정

ititit1.tistory.com

이 글을 올리고나서 엄청높은조회수, 많은 제작문의를 받아왔는데 해당글은 배포용이 아니라 개발공부용으로 올린글이었습니다. 

또한 최근에 업비트 api 변경(docs.upbit.com/changelog/%EC%95%88%EB%82%B4-open-api-%EB%B3%80%EA%B2%BD%EC%82%AC%ED%95%AD-%EC%95%88%EB%82%B4-%EC%A0%81%EC%9A%A9-%EC%9D%BC%EC%9E%90-0322-1) , 최소주문금액500->5000원으로 변경 되면서 새로 단주매매프로그램을  개발하게 되었고

이번엔 유저 배포용으로 프로그램을 만들었습니다.

 

단주매매 프로그램가격은 150,000원에 판매중이며 문의시 자세히 설명해드리고, 문제생기거나 어려운부분은 친절히 도와드리겠습니다. jinsol0321 카톡

 

 

 

 

현재 만들어진 프로그램 기능은 1. 업비트 호가창 흔들기(단주매매)입니다.

 

 

제작문의로 들어온 김프프로그램(거래소와 선물거래소 가격차이를 이용한 리스크없는 매매프로그램) 을 개발중이며 이또한 개발이 잘된다면 유료배포 할생각입니다.

 

단주 매매란?

 

주식 호가창을 보면 매수, 매도 체결 가격과 수량이 나타납니다. 호가창은 주식을 하는 사람이면 가장 쉽게 접할 수 있는 창인 만큼 속임수가 가득합니다. 그 중 단주매매는 호가창 매수1, 매도1 수량이 연속해서 계속 체결되는 것을 말합니다. 하기 그림의 예를 보시면 됩니다.

 

단주매매를 하는 이유?

 

실제 호가창에서 일어나는 단주매매의 체결 속도를 보시면 사람이 매수 주문을 넣고 바로 매도 주문을 넣고 이걸 반복해서 구현 할 수 있는 속도가 아닙니다. 즉 프로그램을 통해 매매를 하는 것입니다. 즉 세력들이 사용하는 매매입니다. 단주 매매가 일어나는 가격을 보면 매수는 한호가 위에서 매도는 한호가 아래에서 거래가 됩니다. 따라서 단주 매매가 발생하면 종목의 가격이 올랐다가 내렸다가 올랐다가 내렸다가를 반복하게 됩니다. 관심종목에 둔 사람들 눈에는 가격이 계속 변하는 것 처럼 보이게 되며 사람들의 이목을 끌게 됩니다. 이처럼 단주매매는 어떤 이유에서든 주가를 움직이는 세력이 사람들의 관심을 끌기 위해 사용합니다. 단주매매가 진행되는 호가창을 지켜보면 사람들의 반응과 세력의 행동을 볼 수 있습니다. 세력의 의도대로 곧 주가가 올라 갈 것 같으니 개미들이 사기 시작합니다.

 

실제로 아는분들은 단주매매를 쓰면서 몇천만원치를 매수해놓고 단주매매를 돌려 가격을 1~3%올린다음

빠르게 매도하여 빠진다고 합니다. 

 

주식에서는 단주매매시 경고1,2,3회 후 거래정지? 벌금으로 알고있는데 가상화폐 거래에서는 단주매매에 대한 제재하지 않습니다. 하지만 거래소쪽과 권장 통신(api주문)이 초당 8회 분당200회로 정해져있지만 딱히 아무런 제제를 당해본적이없어서 잘모르겠습니다. 

 

 

 

www.youtube.com/watch?v=giuPsSeB73w&feature=emb_title

 

728x90

+ Recent posts