From d3b7ccf72f1b5c8b2ae90ef2d09ebe324b98d963 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20S=C3=A1nchez?= Date: Sat, 4 Jan 2025 19:53:36 -0300 Subject: [PATCH] subscribe-redeem test --- libraries/wrappers/earn_binance.py | 21 ++++++-- libraries/wrappers/earn_gateio.py | 33 ++++++++---- libraries/wrappers/earn_kucoin.py | 19 ++++--- libraries/wrappers/earn_okx.py | 10 ++++ main.py | 80 +++++++++++++++++++++++++----- 5 files changed, 132 insertions(+), 31 deletions(-) diff --git a/libraries/wrappers/earn_binance.py b/libraries/wrappers/earn_binance.py index 95eaa7f..336c6e5 100644 --- a/libraries/wrappers/earn_binance.py +++ b/libraries/wrappers/earn_binance.py @@ -40,11 +40,18 @@ class binance_earn: return None - def subscribe_product(self, product_id, amount, auto_subscribe=True, source_account="SPOT"): + def subscribe_product(self, product_id, amount, auto_subscribe=False, source_account="SPOT"): ''' - autoSubscribe (boolean, optional): true or false, default true. + autoSubscribe (boolean, optional): true or false, default false. sourceAccount (str, optional): SPOT,FUND,ALL, default SPOT recvWindow (int, optional): The value cannot be greater than 60000 + + returns { + purchaseId: int, + success: boolean, + amount: str + } + example: {'purchaseId': 7531473612, 'success': True, 'amount': '10'} ''' try: response = self.client.subscribe_flexible_product(productId=product_id, amount=amount, autoSubscribe=auto_subscribe, sourceAccount=source_account, recvWindow=5000) @@ -54,12 +61,14 @@ class binance_earn: return None - def redeem_product(self, product_id, redeem_all=True, amount=0, destination_account="SPOT"): + def redeem_product(self, product_id, redeem_all=False, amount=0, destination_account="SPOT"): ''' - redeemAll (boolean, optional): true or false, default to false + redeemAll (boolean, optional): true or false, default to false (Note: redeemAll=True didn't seem to work) amount (float, optional): if redeemAll is false, amount is mandatory destAccount (str, optional): SPOT,FUND,ALL, default SPOT recvWindow (int, optional): The value cannot be greater than 60000 + + example: {'redeemId': 483738233, 'success': True} ''' try: response = self.client.redeem_flexible_product(productId=product_id, redeemAll=redeem_all, amount=amount, destAccount=destination_account, recvWindow=5000) @@ -76,6 +85,8 @@ class binance_earn: current (int, optional): Current querying page. Start from 1. Default:1 size (int, optional): Default:10 Max:100 recvWindow (int, optional): The value cannot be greater than 60000 + + example: {'total': 1, 'rows': [{'totalAmount': '10.00000299', 'tierAnnualPercentageRate': {'0-500USDT': '0.05000000'}, 'latestAnnualPercentageRate': '0.05229776', 'asset': 'USDT', 'canRedeem': True, 'collateralAmount': '0', 'productId': 'USDT001', 'yesterdayRealTimeRewards': '0', 'cumulativeBonusRewards': '0', 'cumulativeRealTimeRewards': '0.00000299', 'cumulativeTotalRewards': '0.00000299', 'autoSubscribe': False}]} ''' try: @@ -89,6 +100,8 @@ class binance_earn: def get_account(self, recv_window=5000): ''' recvWindow (int, optional): The value cannot be greater than 60000 + + example: {'totalAmountInBTC': '0.00010133', 'totalAmountInUSDT': '10.00000398', 'totalFlexibleAmountInBTC': '0.00010133', 'totalFlexibleAmountInUSDT': '10.00000398', 'totalLockedInBTC': '0', 'totalLockedInUSDT': '0'} ''' try: response = self.client.simple_account(recv_window=recv_window) diff --git a/libraries/wrappers/earn_gateio.py b/libraries/wrappers/earn_gateio.py index 4772d9a..ef53a26 100644 --- a/libraries/wrappers/earn_gateio.py +++ b/libraries/wrappers/earn_gateio.py @@ -58,12 +58,15 @@ class gateio_earn: def get_available_products(self,coin): + ''' + response: {'coin': 'USDT', 'product_id': 'USDT', 'rate': '0.00057', 'min_amount': '1', 'isActive': True} + ''' url = f"/earn/uni/currencies/{coin}" headers = {"Accept": "application/json", "Content-Type": "application/json"} query_param = "" sign_headers = self.gen_sign("GET", self.prefix+url, query_param) headers.update(sign_headers) - response = requests.get(self.host+self.prefix+url, params=query_param, headers=sign_headers) + response = requests.get(self.host+self.prefix+url, params=query_param, headers=headers) if response.status_code == 200: return {"coin": response.json()["currency"], "product_id": response.json()["currency"], @@ -79,7 +82,7 @@ class gateio_earn: headers = {"Accept": "application/json", "Content-Type": "application/json"} sign_headers = self.gen_sign("GET", self.prefix+url) headers.update(sign_headers) - response = requests.get(self.host+self.prefix+url, headers=sign_headers) + response = requests.get(self.host+self.prefix+url, headers=headers) if response.status_code == 200: return {"coin": response.json()["currency"], "product_id": response.json()["currency"], @@ -89,29 +92,41 @@ class gateio_earn: else: return {"Error": response.text} + + def get_min_rate(self,coin): + url = f"/earn/uni/currencies/{coin}" + headers = {"Accept": "application/json", "Content-Type": "application/json"} + sign_headers = self.gen_sign("GET", self.prefix+url) + headers.update(sign_headers) + response = requests.get(self.host+self.prefix+url, headers=headers) + if response.status_code == 200: + return {"min_rate": response.json()["min_rate"]} + else: + return {"Error": response.text} + def subscribe_product(self, coin, amount, rate): url = "/earn/uni/lends" headers = {"Accept": "application/json", "Content-Type": "application/json"} query_params = "" - body = {"currency": coin, "amount": str(amount), "min_rate": rate, "type": "lend"} + body = f'{{"currency": "{coin}", "amount": {amount}, "min_rate": {rate}, "type": "lend"}}' sign_headers = self.gen_sign("POST", self.prefix+url, query_params, body) headers.update(sign_headers) - response = requests.post(self.host+self.prefix+url, headers=sign_headers, data=body) + response = requests.post(self.host+self.prefix+url, headers=headers, data=body) if response.status_code == 200: return response.json() else: return {"Error": response.text} - def redeem_product(self, coin, amount, rate): + def redeem_product(self, coin, amount, rate="0"): url = "/earn/uni/lends" headers = {"Accept": "application/json", "Content-Type": "application/json"} query_params = "" - body = {"currency": coin, "amount": str(amount), "min_rate": rate, "type": "redeem"} + body = f'{{"currency": "{coin}", "amount": {amount}, "min_rate": {rate}, "type": "redeem"}}' sign_headers = self.gen_sign("POST", self.prefix+url, query_params, body) headers.update(sign_headers) - response = requests.post(self.host+self.prefix+url, headers=sign_headers, data=body) + response = requests.post(self.host+self.prefix+url, headers=headers, data=body) if response.status_code == 200: return response.json() else: @@ -127,7 +142,7 @@ class gateio_earn: headers = {"Accept": "application/json", "Content-Type": "application/json"} sign_headers = self.gen_sign("GET", self.prefix+url) headers.update(sign_headers) - response = requests.get(self.host+self.prefix+url, headers=sign_headers) + response = requests.get(self.host+self.prefix+url, headers=headers) if response.status_code == 200: return response.json() else: @@ -136,7 +151,7 @@ class gateio_earn: def amend_rate(self,coin,min_rate): url = f"/earn/uni/lends" - body = {"currency": coin, "min_rate": min_rate} + body = str({"currency": coin, "min_rate": min_rate}) headers = {"Accept": "application/json", "Content-Type": "application/json"} sign_headers = self.gen_sign("PATCH", self.prefix+url, body) headers.update(sign_headers) diff --git a/libraries/wrappers/earn_kucoin.py b/libraries/wrappers/earn_kucoin.py index c3a9349..a6d682e 100644 --- a/libraries/wrappers/earn_kucoin.py +++ b/libraries/wrappers/earn_kucoin.py @@ -68,19 +68,21 @@ class kucoin_earn: "isActive": response.to_dict()["common_response"]["data"][0]["status"]=="ONGOING"} - def subscribe_product(self, product_id, amount, auto_subscribe=True, source_account="SPOT"): + def subscribe_product(self, product_id, amount, auto_subscribe=False, source_account="SPOT"): ''' source_account: "TRADE" or "MAIN" auto_subscribe is ignored here + + response: {'common_response': {'code': '200000', 'data': {'orderId': '2987632', 'orderTxId': '6681886'}, 'rate_limit': {'limit': 2000, 'remaining': 1995, 'reset': 29901}}, 'orderId': '2987632', 'orderTxId': '6681886'} ''' if source_account.upper() in ["SPOT","TRADE","ALL"]: - source="trade" + source="TRADE" elif source_account.upper() in ["FUND","MAIN"]: - source="main" #In Binance SPOT is TRADE and MAIN is FUND + source="MAIN" #In Binance SPOT is TRADE and MAIN is FUND else: return {"Error": "Invalid source_account. Values should be TRADE or MAIN for kucoin, SPOT, FUND or ALL for binance"} - request = PurchaseReqBuilder(product_id=product_id, amount=str(amount), account_type=source).build() + request = PurchaseReqBuilder().set_product_id(product_id).set_amount(str(amount)).set_account_type(source).build() response = self.earn_api().purchase(request) return response.to_dict() @@ -89,6 +91,8 @@ class kucoin_earn: ''' source_account is ignored unless orderID=ETH2: "TRADE" or "MAIN" auto_subscribe is ignored here + + returns {'common_response': {'code': '200000', 'data': {'orderTxId': '6681887', 'deliverTime': 1736027626000, 'status': 'SUCCESS', 'amount': '20'}, 'rate_limit': {'limit': 2000, 'remaining': 1990, 'reset': 9770}}, 'orderTxId': '6681887', 'deliverTime': 1736027626000, 'status': , 'amount': '20'} ''' if source_account in ["SPOT","TRADE","ALL"]: @@ -98,12 +102,15 @@ class kucoin_earn: else: return {"Error": "Invalid source_account. Values should be TRADE or MAIN for kucoin, SPOT, FUND or ALL for binance"} - request = RedeemReqBuilder(order_id=order_id, amount=str(amount), from_account_type=source).build() - response = self.earn_api().purchase(request) + request = RedeemReqBuilder().set_order_id(order_id).set_amount(str(amount)).set_from_account_type(source).build() + response = self.earn_api().redeem(request) return response.to_dict() def get_position(self, coin, **kwargs): + ''' + Return {'common_response': {'code': '200000', 'data': {'totalNum': 1, 'items': [{'orderId': '2987632', 'productId': '2152', 'productCategory': 'DEMAND', 'productType': 'DEMAND', 'currency': 'USDT', 'incomeCurrency': 'USDT', 'returnRate': '0.04767484', 'holdAmount': '20', 'redeemedAmount': '0', 'redeemingAmount': '0', 'lockStartTime': 1641806718000, 'lockEndTime': None, 'purchaseTime': 1736027283000, 'redeemPeriod': 0, 'status': 'LOCKED', 'earlyRedeemSupported': 0}], 'currentPage': 1, 'pageSize': 15, 'totalPage': 1}, 'rate_limit': {'limit': 2000, 'remaining': 1995, 'reset': 16550}}, 'totalNum': 1, 'items': [{'orderId': '2987632', 'productId': '2152', 'productCategory': 'DEMAND', 'productType': 'DEMAND', 'currency': 'USDT', 'incomeCurrency': 'USDT', 'returnRate': '0.04767484', 'holdAmount': '20', 'redeemedAmount': '0', 'redeemingAmount': '0', 'lockStartTime': 1641806718000, 'purchaseTime': 1736027283000, 'redeemPeriod': 0, 'status': , 'earlyRedeemSupported': }], 'currentPage': 1, 'pageSize': 15, 'totalPage': 1} + ''' request = GetAccountHoldingReqBuilder().set_currency(coin).build() response = self.earn_api().get_account_holding(request) return response.to_dict() diff --git a/libraries/wrappers/earn_okx.py b/libraries/wrappers/earn_okx.py index 39a2f2b..c21d2c5 100644 --- a/libraries/wrappers/earn_okx.py +++ b/libraries/wrappers/earn_okx.py @@ -68,6 +68,8 @@ class okx_earn: } ] } + + response: {'code': '0', 'data': [{'amt': '10', 'ccy': 'USDT', 'clientId': '', 'from': '18', 'to': '6', 'transId': '1064005710'}], 'msg': ''} ''' transfer = self.funding_api.funds_transfer(coin,amount,"18","6","0") @@ -93,6 +95,8 @@ class okx_earn: } ] } + + response: {'code': '0', 'data': [{'amt': '20', 'ccy': 'USDT', 'clientId': '', 'from': '6', 'to': '18', 'transId': '1064008141'}], 'msg': ''} ''' transfer = self.funding_api.funds_transfer(coin,amount,"6","18","0") return transfer @@ -123,6 +127,8 @@ class okx_earn: ], "msg": "" } + + response {'code': '0', 'data': [{'amt': '10', 'ccy': 'USDT', 'clientId': '', 'from': '18', 'instId': '', 'state': 'success', 'subAcct': '', 'to': '6', 'toInstId': '', 'transId': '1064005710', 'type': '0'}], 'msg': ''} ''' transfer = self.funding_api.transfer_state(transaction_id) return transfer @@ -141,6 +147,8 @@ class okx_earn: ''' ONLY ASSETS IN THE FUNDING ACCOUNT CAN BE USED FOR SUBSCRIPTION, MOVE THE FUNDS FROM THE TRADING ACCOUNT TO THE FUNDING ACCOUNT BEFORE SUBSCRIBING. + + response: {'code': '0', 'data': [{'amt': '10', 'ccy': 'USDT', 'rate': '0.1091', 'side': 'purchase'}], 'msg': ''} ''' if rate is None: rate = self.get_avg_rate(coin) @@ -151,6 +159,8 @@ class okx_earn: ''' ASSETS REDEEMED WILL BE PLACED IN THE FUNDING ACCOUNT, MOVE THE FUNDS FROM THE FUNDING ACCOUNT TO THE TRADING ACCOUNT AFTER REDEMPTION. + + response: {'code': '0', 'data': [{'amt': '20', 'ccy': 'USDT', 'rate': '', 'side': 'redempt'}], 'msg': ''} ''' return self.earning_api.savings_purchase_redemption(coin, str(amount), "redempt", "0") diff --git a/main.py b/main.py index b39bb0c..81a8a4e 100644 --- a/main.py +++ b/main.py @@ -11,17 +11,73 @@ okx = earn_okx.okx_earn() gateio = earn_gateio.gateio_earn() if __name__=="__main__": - #Available products - print("Binance:") - print(binance.get_available_products("USDT")) - print("="*80) - print("Gate.io:") - print(gateio.get_available_products("USDT")) - print("="*80) - print("Kucoin:") - print(kucoin.get_available_products("USDT")) - print("="*80) - print("OKX:") - print(okx.get_available_products("USDT")) + + ''' + Subscribe workflow in Binance: + 1. Get product id + 2. Subscribe + + Redeem workflow in Binance + 1. Redeem with the same product id + ''' + #print(binance.get_available_products("USDT")) + #print(binance.subscribe_product("USDT001", "10", auto_subscribe=False)) + #print(binance.get_position("USDT")) + #print(binance.redeem_product("USDT001", amount="5.00000746")) + + + + ''' + Subscribe workflow in Kucoin + 1. Get product id + 2. Subscribe + + Redeem workflow in Kucoin + 1. Get ORDER id (the order id of the position) + 2. Redeem + ''' + #print(kucoin.get_available_products("USDT")) + #print(kucoin.subscribe_product("2152", "10")) + #print(kucoin.get_position("USDT")) + #print(kucoin.redeem_product(order_id="2987632", amount="20")) + + + ''' + Subscribe workflow in OKX + 1. Transfer funds to funding account + 2. Confirm transfer via transfer_id + 3. Subscribe + + Redeem workflow in OKX + 1. Reddem product (with coin, no id is required) + 2. Transfer funds to trading account + 3. Confirm transfer via transfer_id + + ''' + #print(okx.get_available_products("USDT")) + #print(okx.transfer_to_funding("USDT","10")) + #print(okx.get_transfer_state("1064007151")) + #print(okx.subscribe_product("USDT", "10")) + #print(okx.redeem_product("USDT", "20")) + #print(okx.transfer_to_trading("USDT", "20")) + #print(okx.get_transfer_state("1064008141")) + + + ''' + Subscribe workflow in Gate.io + 1. Get minimum rate + 2. Subscribe product + 3. Use get_account to confirm (request returns error?) + + Redeem workflow in Gate.io + 1. Reddem product + 2. Use get_account to confirm (request returns error?) + ''' + + #print(gateio.get_min_rate("USDT")) + #print(gateio.redeem_product("USDT", "10", "0.00000452")) + #print(gateio.get_account()) + pass +