BinanceのAPIで使うSHA256の認証をPythonでとおす！

# 導入
CCXTを使えば、大体のAPIはフォローされているのであまり困ることはない。
ただ、どうしてもBinanceのAPI仕様書に記載されているものをそのまま使いたい時がある。
仕様書では一部SHA256の認証を使えと書いてあるけど、具体的なコードが記載されていなくて、またグーグル先生に聞いても参考となるコードがあまり出てきませんでした。（Binance提供するモジュールのソースコードは存在したので参考にした）
そのため、誰かの参考になればと思い記載します。


# 参考プログラム（ステーキングのポジションを取得する）
```python:main.py
import math
import time
from typing import Dict, Optional, List, Tuple
from binance.client import Client
from operator import itemgetter
import requests
import hmac
import hashlib

#色々パラメータ設定
api_key = "バイナンスで発行するAPIKEY"
api_secert = "バイナンスで発行する秘密鍵"
binance_api = "https://api.binance.com"
timestamp = time.time() * 1000 
header = {"X-MBX-APIKEY" : api_key}

#サーバータイムを取りに行くまで先にやってしまう。特に先にやる意味はない。
#実際はここもAPIでとれるけど今回はパス
Client = Client(api_key,api_secert)
res = Client.get_server_time()
timestamp_offset = res['serverTime'] - int(timestamp)
ex_timestamp = timestamp + timestamp_offset
    
########################sha256のハッシュ生成（関数）############################
def _generate_signature(data: Dict) -> str:
    assert api_secert, "API Secret required for private endpoints"
    ordered_data = _order_params(data)
    query_string = '&'.join([f"{d[0]}={d[1]}" for d in ordered_data])
    m = hmac.new(api_secert.encode('utf-8'), query_string.encode('utf-8'), hashlib.sha256)
    return m.hexdigest()

def _order_params(data: Dict) -> List[Tuple[str, str]]:

    data = dict(filter(lambda el: el[1] is not None, data.items()))
    has_signature = False
    params = []
    for key, value in data.items():
        if key == 'signature':
            has_signature = True
        else:
            params.append((key, str(value)))
    # sort parameters by key
    params.sort(key=itemgetter(0))
    if has_signature:
        params.append(('signature', data['signature']))
    return params

##################ステーキングのポジションをゲットする（関数）######################
def Staking_get():
    rtn = {}
    #sha256で必要なパラメータを設定
    q = {"product" : "STAKING" ,"recvWindow" : 5000 ,"timestamp" : int(ex_timestamp) }
    #sha256のハッシュ生成
    qq = _generate_signature(q)
    #ハッシュを追加
    q["signature"] =  qq
    #APIを投げる！
    r  = requests.get(binance_api+"/sapi/v1/staking/position",params = q ,headers = header )
    print("Stakingのレスポンス :" , r)#200が返ってくるとOK
    staking_asset = r.json()#返されたJSONを取り出す。
    
    #結果を{"通貨：保有量"}という形にしてrtnに入れていく、重複がある場合は合計を求める。
    for i in staking_asset:
        if i["asset"] in rtn:
            exit_postion = float(rtn[i["asset"]])
            new_postion  = float(i["amount"]) + exit_postion
            rtn[i["asset"]] = new_postion
        else:
            rtn[i["asset"]] = float(i["amount"])

    #DeFi Stakingのポジションをゲットする用
    q2 = {"product" : "L_DEFI" ,"recvWindow" : 5000 ,"timestamp" : int(ex_timestamp) }
    qq2 = _generate_signature(q2)
    q2["signature"] =  qq2
    r2 = requests.get(binance_api+"/sapi/v1/staking/position",params = q2 ,headers = header )
    asset2 = r2.json()
    #DeFiの場合は基本的には重複はしないはずだから重複を考慮しない
    for ii in asset2:
        rtn[ii["asset"]] = float(ii["amount"])
    print(rtn)
    return (rtn)#戻り値必要な時

######################### Main #########################
Staking_get()
```

後はパラメータ変えると好きなように出来るはず！
# 参考
・BinanceのAPI仕様書
https://binance-docs.github.io/apidocs/#change-log