[암호화폐] BSC에서 파이썬으로 자동매매(1)

in SCT.암호화폐.Crypto3 years ago (edited)

암호화폐 시장이 변동성이 좋기 때문에 자동매매하기 좋은 환경입니다.

요즘 주로 투자하고 있는 코인이 DEC과 SPS인데요. 매일 airdrop 받는 수량을 전량 스테이킹만 하고 있었는데.. sps 가격 변동성이 너무 좋아서 일부 수량은 박스권 매매에 도전해보기로 했습니다.

bsc에서 매매는 swap인데요. 이전에 설명하였듯이 스왑은 LP에서 토큰 A를 주고 B를 받거나 토큰 B를 주고 A를 받는 행위입니다.

swap의 원조는 uniswap이죠. 그래서인지 api도 eth 기반으로 나와있습니다. 다행히 bsc도 eth 기반이므로 provider 정보만 bsc로 변경하면 사용할 수 있습니다.

eth기반 블록체인을 사용할 수 있는 api가 Web3 입니다. web3는 nodejs 예제가 많습니다만 전 파이썬 밖에 모르므로 파이썬으로 할 수 있는 web3 package를 사용하여야 합니다.

https://web3py.readthedocs.io/en/stable/index.html

사용하는 절차는 아래와 같습니다.

우선 web3 패키지를 설치합니다.

pip install web3

자세한 사항은 위에 있는 web3py 사이트에 나오는 내용을 참고하세요.

그러면 이를 기반으로 bsc에서 sps, dec 토큰의 현재가격을 얻는 방법을 알아보겠습니다.

우선 bsc용 provider를 생성합니다. bsc provider 주소는 아래와 같습니다. 그리고 연결이 잘 되었는지 확인하는 코드입니다.

w3 = Web3(Web3.HTTPProvider('https://bsc-dataseed.binance.org/'))
print(w3.isConnected())

swap은 pancakeswap을 사용하도록 하겠습니다. 그 이유는 sps/bnb가 pancakeswap에 등록되어 있기 때문입니다.

exch_addr = '0x10ED43C718714eb63d5aA57B78B54704E256024E'   # pancakeswap v2

sps, dec의 주소를 확인해봅니다. 처음으로 사용하는 토큰인 경우에는 coinmarketcap에서 정확한 smart contract 주소를 확인하시기 바랍니다. 만약 본인이 swap한 이력이 있다면 bscscanc.com에서 확인도 가능합니다.

거래에 사용할 토큰들의 주소를 정리합니다.

sc_tokens = {
    'bnb' : '0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c',
    'wbnb1' : '0x24f7C33ae5f77e2A9ECeed7EA858B4ca2fa1B7eC',
    'busd' : '0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56',
    'dec' : '0xE9D7023f2132D55cbd4Ee1f78273CB7a3e74F10A', 
    'sps' : '0x1633b7157e7638C4d6593436111Bf125Ee74703F'
}

특정 토큰의 현재 가격을 구하는 방법은 여러가지가 있습니다. 이전 x*y=k 에 대한 글에서 보시면 특정 LP에 있는 토큰 A, B의 가격은 해당 LP에 있는 각 토큰의 수량을 나눈 값이 가격입니다. 이렇게 특정 LP의 smart contract 주소를 찾은 후 token a, b의 수량을 구한 후 수량을 나누어서 구할 수 있습니다.

하지만 본 프로젝트에서는 swap까지 해야하기 때문에 swap시 받을 수 있는 코인 수량을 받아서 가격을 역추산해보겠습니다.

LP 기준으로 A토큰을 B토큰을 바꾸는 경우와 그 반대의 경우에 사용하는 함수가 틀립니다.

아래는 A 토큰을 넣었을 때 받을 수 있는 B 토큰 수량을 얻을 수 있는 함수입니다. 여기에서 path는 토큰 A, 토큰 B의 smart contract로 이루어진 list입니다. 중간에 한 단계를 더 거치는 경우에는 해당하는 모든 토큰의 smart contract가 포함되어 있어야 합니다.

이 두 함수가 조금 헷갈리는데요. 매수/매도시 함수명이 틀리므로 잘 이해를 하셔야 합니다.

ret = exchange.functions.getAmountsOut(amountIn=amount, path=pair).call() # A -> B
ret = exchange.functions.getAmountsIn(amountOut=amount, path=pair).call() # B -> A

A를 B로 바꾼다는 행위는 A 토큰을 추가하고 B 토큰을 인출, 그 반대는 A토큰이 추가되는 개념으로 이해하시면 됩니다. 함수명이 그런 의미를 가지고 있습니다.

getAmountsOut() 함수의 ret 값에는 path별 코인의 수량이 들어있습니다. 만약 path가 두개라면 ret[0]에는 A토큰 수량(매도할 토큰 수), ret[1]에는 받을 토큰 수량이 들어있습니다.

getAmountsIn() 는 ret[0]에는 받을 값, re[1]에는 보낸 값이 들어있습니다. 두 함수의 ret 값의 의미를 잘 확인하셔야 오류를 막을 수 있습니다.


기본 함수에 대한 설명을 마치고, 현재가를 확인해보는 코드를 만들어 보겠습니다.

본 프로젝트에서는 sps를 busd로 혹은 그 반대로 swap하는 코드를 만들고자합니다. bnb가 아닌 busd로 하는 이유는 bnb의 가격 변동을 무시하기 위함입니다.

현재 sps/bnb LP의 TVL이 높으므로 아래와 같이 두 단계를 거쳐서 swap하도록 하겠습니다.

sps -> bnb -> busd

이렇게 되면 path에 위 주소 3개가 필요합니다. 역인 경우에는 반대 순서로 들어가면 됩니다.

우선 거래할 pair를 기술할 구조를 만들어봅니다.
거쳐갈 토큰들과 수량을 입력합니다.
거쳐갈 토큰을 자동으로 구하는 방법은 아직 발견하지 못하여 수동으로 기록했으니 참고하십시요.

    trading_pair = [
        {'from':'sps', 'mid': 'bnb', 'to':'busd', 'amount':100},
    ]

이렇게 해서 동작하는 모습은 아래와 같습니다. 현재 pancakeswap에 나오는 수량과 정확하게 일치합니다.

관련 소스는 아래 gihub에 있습니다.

https://github.com/multizone-quant/system-trading-bsc/blob/main/get_cur_token_price_bsc.py

Sort:  

@tradingideas transfered 27 KRWP to @krwp.burn. voting percent : 100.00%, voting power : 37.30%, steem power : 1852079.01, STU KRW : 1200.
@tradingideas staking status : 21190 KRWP
@tradingideas limit for KRWP voting service : 21.19 KRWP (rate : 0.001)
What you sent : 27 KRWP (Voting Percent over 100 %)
Refund balance : 15.287 KRWP [57811622 - 0cadce5a9f4d0816e0f9ac23a414a8c9093bdb43]

정말 대단하신 트아님입니다.

Coin Marketplace

STEEM 0.26
TRX 0.11
JST 0.032
BTC 63547.08
ETH 3070.13
USDT 1.00
SBD 3.83