From 50fdb40a62c70f7cef477a046b492168b370dce1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20S=C3=A1nchez?= Date: Wed, 1 Jan 2025 15:53:08 -0300 Subject: [PATCH] Initial commit --- .gitignore | 1 + __pycache__/balance_accounts.cpython-311.pyc | Bin 0 -> 889 bytes __pycache__/credentials.cpython-311.pyc | Bin 0 -> 1081 bytes __pycache__/earn_binance.cpython-311.pyc | Bin 0 -> 10457 bytes __pycache__/earn_gateio.cpython-311.pyc | Bin 0 -> 3914 bytes __pycache__/earn_kucoin.cpython-311.pyc | Bin 0 -> 8402 bytes __pycache__/earn_okx.cpython-311.pyc | Bin 0 -> 5986 bytes .../balance_accounts.cpython-311.pyc | Bin 0 -> 899 bytes libraries/balance_accounts.py | 22 +++ .../__pycache__/earn_binance.cpython-311.pyc | Bin 0 -> 10476 bytes .../__pycache__/earn_gateio.cpython-311.pyc | Bin 0 -> 3933 bytes .../__pycache__/earn_kucoin.cpython-311.pyc | Bin 0 -> 8421 bytes .../__pycache__/earn_okx.cpython-311.pyc | Bin 0 -> 6005 bytes libraries/wrappers/earn_binance.py | 169 ++++++++++++++++ libraries/wrappers/earn_gateio.py | 69 +++++++ libraries/wrappers/earn_kucoin.py | 127 ++++++++++++ libraries/wrappers/earn_okx.py | 183 ++++++++++++++++++ main.py | 17 ++ 18 files changed, 588 insertions(+) create mode 100644 .gitignore create mode 100644 __pycache__/balance_accounts.cpython-311.pyc create mode 100644 __pycache__/credentials.cpython-311.pyc create mode 100644 __pycache__/earn_binance.cpython-311.pyc create mode 100644 __pycache__/earn_gateio.cpython-311.pyc create mode 100644 __pycache__/earn_kucoin.cpython-311.pyc create mode 100644 __pycache__/earn_okx.cpython-311.pyc create mode 100644 libraries/__pycache__/balance_accounts.cpython-311.pyc create mode 100644 libraries/balance_accounts.py create mode 100644 libraries/wrappers/__pycache__/earn_binance.cpython-311.pyc create mode 100644 libraries/wrappers/__pycache__/earn_gateio.cpython-311.pyc create mode 100644 libraries/wrappers/__pycache__/earn_kucoin.cpython-311.pyc create mode 100644 libraries/wrappers/__pycache__/earn_okx.cpython-311.pyc create mode 100644 libraries/wrappers/earn_binance.py create mode 100644 libraries/wrappers/earn_gateio.py create mode 100644 libraries/wrappers/earn_kucoin.py create mode 100644 libraries/wrappers/earn_okx.py create mode 100644 main.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f9b48b3 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +credentials.py diff --git a/__pycache__/balance_accounts.cpython-311.pyc b/__pycache__/balance_accounts.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0ee08675b64c54a6e4cc0f6b9478e69bb8d2512e GIT binary patch literal 889 zcma)4zi-n(6u!&vp6ybVLfR%EA_WDb2Db|=kfG{=geoK^SS;5$1rsNZ&W?a6l^7T@ zvNaMr6tQINpK-PrA}=5z1~#LJr4#Smq^TeSC;9xn=kI;r^WFQXCoGgQYlGZMU0@IWn^tU|>R>Z3mHLD*0AfOVMmW;!B=`sp4x zet_KP^L#(qjP=+(@x2K=gqQ?4*;7CP^Z?}n;r2?*5RQnEm?83K48g_!?=}){iK$yr zcuc#vy2$wgH#6ss1b3#91&q%+uH!>2qDDfT*8We?uZqK@ap0<%P&<)dcx;C|aW8|s; literal 0 HcmV?d00001 diff --git a/__pycache__/credentials.cpython-311.pyc b/__pycache__/credentials.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4acc2f7f82be99dce04187e40e3d28f80d3a837e GIT binary patch literal 1081 zcmZvbO>f&q5Qa%fmSj0LTLW?I1ZdneK;fdQ$mMdmM2o_bY{y7k*|kz7au3FGcPZ17 zNSTxn*^q!7dJuBTtvwaJ75yVU3poiq1?V3z;9E{vs-iPshPIG=7vd@9;R4kI2Y@KIVU+KvNy!MAaa6O_!n{Ox<6YK z#L|cUOc7gtREajdo8?w{%wet{(2W(PsSz-7yZ#O4#1rE7j@l;}@-RrQA3yKB_*d7lY>}d4iuc zN=J6*sZnlt-=AvR#lWpJ&VnX2d!14xmos+z88 z7J?TKO<)lnm@MyTrkRI^uH~^~vph6yjW~vlsO3ai?yp)_U)G2<-umx z^*w}8lx~nN7gN^7ZrHG(!qKB4J_6r@c1!x?$lU z@J~4v0pI?Lt;&HJo#Tu2TJXCpeN*ZB^I7od$J1q#D&`n1zH>?>#Xcx55Sng7eP9|89Yf!w%e2*{hJc=I5M(F&7xg zPXk|i3dXJ}w^?AO17)WDGT}D_wM*|D-ZqSq8+K~EVI~EFV{&S|33cMgSeimK+ljhU z>O>VfwK&<9mY%S%Px1So^-h@?t=G^MGc8-aL#C3;zzeW?j}UVj-m%rIXy@rP^x`{| zydL3QIx$Jo4c(Tc{KnvP^^~$vc&$DlZ!>qg`#;}*yL}_B=3`VOpo*>K-5ZlUK^Y>s9z) z^E2kS0*FeRpB`e~+%(4*Kyb==1@;W>k;EaNFXt-&rxE78HZ=m1F64h17ro=CX6J}u ziT0ExP7qBK<#V#0mdDeYI4-9VFrqmj%A#WGh6pE?vx%(g#-u1KikUNPvD+jxUpt%A z&&g?+dH}h(vE(lGk!x4874RC9taX29URzt&t;xj*SXA> z%9HibdPoRjkU@pO0p>DOy9O~Ru&5PP{(9spJoPnva(bXZj4+*y?dLGeR)*}J2 z@vXTXZWaikss+;-&9dZ4nw5;Xa?^#cIiRnliL`cJ2XU6N#8h*NEv0qKCivuzkR>{d zBRXM{jBGn~Zif=~;>777T)x5Oz1}>DBnfOHMl>)HhNU?IEp(4qwo(I8LR4u8R=%@B zGJV+jg%G^f?|^`CazgDUkhDv0eVN#|kl1(2F1~rXs7)1fv&F=|+ll;QB0s-xsil4X z@OO8bo-o*B6_Izid9X(0r_T{N&>C$)av7>a)ur18j=>7B7dnZy2WK2qu66 z-|%zffkG*uOD&0u&zFAR!LckrA8@tso&M^n4(6kH>KXoef2xbW*(Crw3g+<0;Zenx zF(~KD{y!kGR@pCb1-=kb+3Va@XzQBa-keYns!D$}B>nsf(jN^-e>5Qd(do5Ie`GFt zA&M$hrCdPzh5T2(s*`iJIg%T<6rzu7V)wXdrZw5vA(~lRHw`(R8~}})13gQ`2{~

Mdu(`UN9y3gavPZKH&Mo#*bSl|sy_;v z9ke$LM3D`{v_%-~B++DWhd{f_hWNrxI8f!5n|l)8V^VNxJ#6h)ov55ao8UBrp4w>$ z4W5Wlk30=zxP;p$tkMisAeMrabYhjQNV<@0L$V!6vc@$K@e;mumGnTq(}*LG{AQg- zcL89CUybJHf0fIKpzo$?^5)Noy^Da)U*6&{i$vI&20j(1igqKD|Y21 zSgx{=YpSMYQt9-ALDzJ_>^I}$LhPPMn{pU<`h-aQK6I<31iT86k&z8mhCpT3Z%oxJ z`w=Swe=NjR0^~W67^l{M5*LJZfss~0eZnpNpFy7d1bYPk0pE`#r_*kiE!ZW*dZ=92 z0`^9)0Z)JA+e1hX-`oj3mSEmkhWWrkV&KMD@uXHXY{2&*cN}4^aFYP@0fhM!h56K@ zf;o8s(Hsmh&=S|d|L)&_pe5!)erP$CQ+XZSgFmppVb|zwvMbozhv98<)Y}A~SEXFQ z-bUoMAZBSqA$EsNq%X0)wOX-+=b}~`$wAk570>20GK(=#7W~g1am1F14e^ti5&L?? zA=i8l^!Yuar(4;WUv8&(NIpN%w{xdo;b9wUYHL4*wGr1#eiHrC3ePxeS~{X;b%Xn< z7m-EJ%*bTY3fR#I$Wqye)?*)~Ci86}R0VJCfm+u4K)`f1Q%t>l(Z2N7V&dgu;sBgC zUU09E)I_$lGVjMzTlf$AQ*HdsHUU_w_o|0>iyo-%AK@3+>-Q|UtPy71{}5(8g&7Yp zqg)VX`G@IC`qGYTW+?H}42=WBo?)XG&6WH%3;+yJa^A<_56nPQ^vcH+Qd;y_3&Stz#5l{VcOw!l#<01Hl4qpnCO z>RL%WBY~(Z5{SAY4-j?nbCC+YlZA(D@&b(#;h-Zl;v>H zRgiQA-vH`@hZf8ZX;Cqa+o{ys+*qWdY? z()Oz>x+SZ-HL!d|>`^^a#nU)8Iw;z32a05}xQv^ze0*qz`rws*m=4k^`oW9%>5`2E zw#p>x>iU7C5Vv8&Llr@lmZ~U%Dy1f{!9Tl-pw%@V z+)q3h+}*(P|6upmKv#=~X!sIB=a!K5#>ve5ci7yB4OX<1@2D`*6=lu`aJj+7Wy&?s zsbb=FIB)EAua7A%9Uc~pe+0haKYf#D&t}0$!s-Alz0<|=S4<;k?GTT?nmRbT|In+* zok$%W8u4q~-+Vtlw%Li`^HuS9H{XL9h~HI9nu7f>SX*4(n!)BgZo`seNLKfD=~gV! zLXB71ioK`Ay9lDc00A#|oeQEpE{OIN6Qgk6KyvH2n|KV7bP&d__*Y}!go2_ujno#`N@a8@&(@$;KDRr8m0WR|A&-WFUM#o?JFM1EzN^C0R4aA`+Oz%&1Xs&koD8`*87d~MTlwPn6kPF46PJ1X zu;T6+x3)3Aji;XGKkiR$=5KBmfQ7F=M#;1Aa7liY?m)Q-*4<)Y$q3$R!f$pAIipFE z6PKh6?CQhrzU0(P5Vp%{_YPSHMG0=9lV_0p6v-|mgGlxvc^%1NBu9~)Kr)5|R|)8c z8+132;PxOTwZK^a0`j*1Tjn_7CD>{&k$8;&ABy;7LsWo`c%L-aVKPiM*JECoY-z+i zpLE0oTvn=}t(7@Vv}Ay8ZKOE?+EGt)D(IF5nqQr|(}6QFoUC#eRS4?U(S&TPF+0^r@@o%9{QPt3o1IX;mQ6!_LBQTcaw3b1}-&Y{Tj$J y&$8??$Fq@T21$%zw-%Ys;JL(XFNV)0rmGk}mm{Y*7Uy#1%Qx=5Z&xWoC*$ApnG1FR literal 0 HcmV?d00001 diff --git a/__pycache__/earn_gateio.cpython-311.pyc b/__pycache__/earn_gateio.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6f2d743a7d7094a7dbf18fc8251704db42db9ef2 GIT binary patch literal 3914 zcmb_f&2Jk;6rcU@N1QlLu-lpzf}0>(^HD>aP})X;(gGDK0nxz00#=)yiL>o`*UYXH zVmYWtJs4C02c&Y~5D=7B<-m!*BZ(|ETG10HZbspNIPu=@dht4;w1~0y?R?K~-h00{ zv)`xFDFP`!U$0mRLVm$QH_1U}`y6Dh5lYI03REQ|hkD7yovYx)^OXQtz(&sgSyUa51{(Jj+WyaZjL)lFgM zEmMblQE&$<%u!%6ngLD|=5Zy~hpe0R5p)^b%fKBfM7_d*>QgA<-(1Rle zc?q8FPdyk;Pa74kL+Msn^A12>6;?$D`v<8hG{qmpsHRsX2WJhE19t7ErWBnqT51xd zYjdzRz?Np+xR1Lix)LbRjoVD)%qhk=&dRYnkE1|HZW4Eg$_7KpHZvC7M4)*$g&BXa z8`nI;**LlY>Cfj%i&mADOkJ}K)h?a2w0adRY?t2P) zjxfE+oH{q{g0sj93!Jfnx}@rcI&ZMTylSYX#tPO#K`m&OZWiE={T!}R-K-Q;O|$Bz zQ#fpKub#bM*OycSbP_fNBiIMpqH0!HF!C^5f!y1iQDO+>>ba(Lf!q{l z-K19MoSE86QRc%it(!G;+fg7!DM5?QY&YRp3e`2ojjOd9Gbs=Twa4=~BHf)r!J+OT z5DGlSFUY#Xsy1p7eJHTjUN44q-AAc$i`Ib^jq!eig)SEMK?B(o#AULTf9R|9?fi+& z{E3bHsdoNUE4{Th-x}P?9qbTs;Fu>`XSXuh&zhe!KmPFQhhJW7XNouGHZ#wxXP(&_ zIdFSqd~;-cZSwo+Z>GPV`F3Vw+q zp&iX*u>Lj%GEhz?+j2bo93AN2(DTQjQ!jpg2rAqZXOyw3q8bK2j1^hRY)3b}6Y8H} z4+nz+1vK{eVve?rYiGQE;j@?Vh*g@}8 zNN;`sp!d<*X58a8#9nH1bQt~!_KNrL83?Q`Da*P^tz~`?THOKfm_l}QG?|Sy@%S7N z+P{?eLB6rCU*&;&KaL~uasuAz^ECg(YqxV#o4Kit-0^nqcxzxQ_i!I|uQtDYwVgS1 zBe$7(YCZGRy^=N(!|&=!Makbe`a3^{5YY?5P_@tV8Mwe%rfMh#TX2;3>z1Q7Ci-`Y zx4gbiINg77Z+;YUpvQD0rUxV7dkr010UKGI?u4;Rr{n({j6J9gq;NF?;$Xinc62!v zf#6D~&!4|<6S=ap0!rR#Bk%C%3_=05l|^t;i?8fF{QEjQA3+qM{@wjW?(r9li9R41 za^N%pAM&WDh$U*AE$M8z@o2xQcI$N}f^D`a&hbZ~swmBQ!Q3whd^9CK#1i!Br1~8qSxA2mkcNP z$Eo^9L?`WQ-EEB!mA`S^^K5azO(+U{-hpyl)715I!v^+;Mf) zu>J1~Piav_{+XQijWxqxgOTWab^}C55(J?mih>Lg5k!&*XM}a~;@$sSWMVz~@5s{v QsCTFM4eNg2rNP_lUuJ!nxc~qF literal 0 HcmV?d00001 diff --git a/__pycache__/earn_kucoin.cpython-311.pyc b/__pycache__/earn_kucoin.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e87ee8caccc3a815d552182e6976b1d939228e49 GIT binary patch literal 8402 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 QYHRurTK~_7aH%K$8&P@N!~g&Q literal 0 HcmV?d00001 diff --git a/__pycache__/earn_okx.cpython-311.pyc b/__pycache__/earn_okx.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1c61d9567ef0650431b3ae8e4dbc3472564d3459 GIT binary patch literal 5986 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 literal 0 HcmV?d00001 diff --git a/libraries/__pycache__/balance_accounts.cpython-311.pyc b/libraries/__pycache__/balance_accounts.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a9804457b1567d898dfb49598e49b76253e15003 GIT binary patch literal 899 zcma)4zi-n(6u!&vp6ybVLfR%EA_WDb2Db|=C__~VA)yM12^Pz7PQk>9qq8F*N+kw{ zjBJg>4n-^(`)8ajhR6#@h=I*0V(G*?H)$&9z)3!T@A-S*_k8z0DhffczP@KoD~Zr| z5zH5!fvF7O5H-+S^b9rd6Qm~0^qd6m6g*IirmIkKhz4kY`w$LNePA7=y}6Fap+UM2 zjvpZR`7A$3wqiYYPke6y4GDMN7a|GSNaTVm!` z6dtoKu3qGPj+hrWDs_-KIuD;vD11&YQMZING~-wKkJFBXqhk(3`50#fFrd{jK%2-ID!?oM)R zqa{CA8p;b4r7xsL1m)J=wSsJkXG?-D`?)gI<=2PuH)wZ@OBJ4~OyQ@|zKY{x_=Fft m91JRKC%OA=r_r-%ja`B;KB4OXq9n#RN?gIWBJ}ST*Z%?3rs$vm literal 0 HcmV?d00001 diff --git a/libraries/balance_accounts.py b/libraries/balance_accounts.py new file mode 100644 index 0000000..92bf94e --- /dev/null +++ b/libraries/balance_accounts.py @@ -0,0 +1,22 @@ +def balance_accounts(spot_balance, earn_balance, lower_limit, step_size, percentage): + target_spot_balance = (spot_balance + earn_balance) * percentage + + while abs(spot_balance - target_spot_balance) >= step_size: + if spot_balance < target_spot_balance: + spot_balance += step_size + earn_balance -= step_size + elif spot_balance > target_spot_balance: + spot_balance -= step_size + earn_balance += step_size + + # Ensure spot_balance is above lower_limit + while spot_balance < lower_limit and earn_balance >= step_size: + spot_balance += step_size + earn_balance -= step_size + + # If earn_balance is not enough, transfer the remaining amount + if spot_balance < lower_limit: + spot_balance += earn_balance + earn_balance = 0 + + return [spot_balance, earn_balance] \ No newline at end of file diff --git a/libraries/wrappers/__pycache__/earn_binance.cpython-311.pyc b/libraries/wrappers/__pycache__/earn_binance.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..958bd0b916a4bd147daf6f28ede87a6ddcf954c2 GIT binary patch literal 10476 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 literal 0 HcmV?d00001 diff --git a/libraries/wrappers/__pycache__/earn_okx.cpython-311.pyc b/libraries/wrappers/__pycache__/earn_okx.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5211b8721125ff710a4dcf73b49fafaa4085dbc4 GIT binary patch literal 6005 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 Pd((eY{(oN4ORe)?fnaHq literal 0 HcmV?d00001 diff --git a/libraries/wrappers/earn_binance.py b/libraries/wrappers/earn_binance.py new file mode 100644 index 0000000..b5856dd --- /dev/null +++ b/libraries/wrappers/earn_binance.py @@ -0,0 +1,169 @@ +''' +https://github.com/binance/binance-connector-python/blob/master/binance/spot/_simple_earn.py + +''' +from credentials import get_api_key +from binance.spot import Spot as Client +from binance.error import ClientError + +class binance_earn: + def __init__(self): + self.api_key, self.api_secret = get_api_key("binance") + self.client = Client(self.api_key, self.api_secret) + + + def get_trading_balance(self, coin): + ''' + Returns the free available balance of a coin in the trading account (or the equivalent account in the exchange) + ''' + account = self.client.account() + for item in account["balances"]: + if item["asset"]==coin: + return item["free"] + + + def get_available_products(self, coin): + try: + response = self.client.get_simple_earn_flexible_product_list(asset=coin, current=1, size=100, recvWindow=5000) + return response + except ClientError as error: + print("Found error. status: {}, error code: {}, error message: {}".format(error.status_code, error.error_code, error.error_message)) + return None + + + def subscribe_product(self, product_id, amount, auto_subscribe=True, source_account="SPOT"): + ''' + autoSubscribe (boolean, optional): true or false, default true. + sourceAccount (str, optional): SPOT,FUND,ALL, default SPOT + recvWindow (int, optional): The value cannot be greater than 60000 + ''' + try: + response = self.client.subscribe_flexible_product(productId=product_id, amount=amount, autoSubscribe=auto_subscribe, sourceAccount=source_account, recvWindow=5000) + return response + except ClientError as error: + print("Found error. status: {}, error code: {}, error message: {}".format(error.status_code, error.error_code, error.error_message)) + return None + + + def redeem_product(self, product_id, redeem_all=True, amount=0, destination_account="SPOT"): + ''' + redeemAll (boolean, optional): true or false, default to false + 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 + ''' + try: + response = self.client.redeem_flexible_product(productId=product_id, redeemAll=redeem_all, amount=amount, destAccount=destination_account, recvWindow=5000) + return response + except ClientError as error: + print("Found error. status: {}, error code: {}, error message: {}".format(error.status_code, error.error_code, error.error_message)) + return None + + + def get_position(self, **kwargs): + ''' + asset (str, optional) + productId (str, optional) + 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 + ''' + + try: + response = self.client.get_flexible_product_position(**kwargs) + return response + except ClientError as error: + print("Found error. status: {}, error code: {}, error message: {}".format(error.status_code, error.error_code, error.error_message)) + return None + + + def get_account(self, recv_window=5000): + ''' + recvWindow (int, optional): The value cannot be greater than 60000 + ''' + try: + response = self.client.simple_account(recv_window=recv_window) + return response + except ClientError as error: + print("Found error. status: {}, error code: {}, error message: {}".format(error.status_code, error.error_code, error.error_message)) + + + def get_personal_left_quota(self, product_id, **kwargs): + ''' + + ''' + try: + response = self.client.get_flexible_personal_left_quota(productId=product_id, **kwargs) + return response + except ClientError as error: + print("Found error. status: {}, error code: {}, error message: {}".format(error.status_code, error.error_code, error.error_message)) + + + def get_subscription_record(self, **kwargs): + ''' + productId (str, optional) + purchaseId (str, optional) + asset (str, optional) + startTime (int, optional): UTC timestamp in ms + endTime (int, optional): UTC timestamp in ms + 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 + ''' + try: + response = self.client.get_flexible_subscription_record(**kwargs) + return response + except ClientError as error: + print("Found error. status: {}, error code: {}, error message: {}".format(error.status_code, error.error_code, error.error_message)) + + + def get_redemption_record(self, **kwargs): + ''' + productId (str, optional) + redeemId (str, optional) + asset (str, optional) + startTime (int, optional): UTC timestamp in ms + endTime (int, optional): UTC timestamp in ms + current (int, optional): Current querying page. Start from 1. Default:1 + size (int, optional): Default:10 Max:100 + ''' + try: + response = self.client.get_flexible_redemption_record(**kwargs) + return response + except ClientError as error: + print("Found error. status: {}, error code: {}, error message: {}".format(error.status_code, error.error_code, error.error_message)) + + + def get_rewards_history(self, type="ALL", **kwargs): + ''' + type (str): ALL, Bonus, REALTIME, REWARDS + productId (str, optional) + asset (str, optional) + startTime (int, optional): UTC timestamp in ms + endTime (int, optional): UTC timestamp in ms + ''' + try: + response = self.client.get_flexible_rewards_history(type=type, **kwargs) + return response + except ClientError as error: + print("Found error. status: {}, error code: {}, error message: {}".format(error.status_code, error.error_code, error.error_message)) + + + def get_subscription_preview(self, product_id, amount, **kwargs): + ''' + args + product_id (str) + amount (float) + + kwargs + recvWindow (int, optional): The value cannot be greater than 60000 + ''' + try: + response = self.client.get_flexible_subscription_preview(productId=product_id, amount=amount, **kwargs) + return response + except ClientError as error: + print("Found error. status: {}, error code: {}, error message: {}".format(error.status_code, error.error_code, error.error_message)) + + + + diff --git a/libraries/wrappers/earn_gateio.py b/libraries/wrappers/earn_gateio.py new file mode 100644 index 0000000..3ee8e5a --- /dev/null +++ b/libraries/wrappers/earn_gateio.py @@ -0,0 +1,69 @@ +''' +https://www.gate.io/docs/developers/apiv4/#earnuni +''' + +from gate_api import ApiClient, Configuration, EarnApi, EarnUniApi +from credentials import get_api_key + +class gateio_earn: + def __init__(self): + api_key, api_secret = get_api_key("gateio") + config = Configuration(key=api_key, secret=api_secret) + self.earn_api = EarnUniApi(ApiClient(config)) + + + def get_trading_balance(self, coin): + ''' + Returns the free available balance of a coin in the trading account (or the equivalent account in the exchange) + ''' + return 0.0 + + def get_available_products(self, coin): + currency_list = self.earn_api.list_uni_currencies() + return_list = [] + for item in currency_list: + if item.to_dict()["currency"] == coin: + return_list.append(item.to_dict()) + return return_list + + + def subscribe_product(self, product_id, amount, auto_subscribe=True, source_account="SPOT"): + return None + + + def redeem_product(self, product_id, redeem_all=True, amount=0, destination_account="SPOT"): + return None + + + def get_position(self, **kwargs): + return None + + + def get_account(self, coin, recv_window=5000): + return_list = [] + earn_list = self.earn_api.list_user_uni_lends() + for item in earn_list: + if item.to_dict["currency"]==coin: + return_list.append(item.to_dict()) + return return_list + + + def get_personal_left_quota(self, product_id, **kwargs): + return None + + + def get_subscription_record(self, **kwargs): + return None + + + def get_redemption_record(self, **kwargs): + return None + + + def get_rewards_history(self, type="ALL", **kwargs): + return None + + + def get_subscription_preview(self, product_id, amount, **kwargs): + return None + \ No newline at end of file diff --git a/libraries/wrappers/earn_kucoin.py b/libraries/wrappers/earn_kucoin.py new file mode 100644 index 0000000..95281fd --- /dev/null +++ b/libraries/wrappers/earn_kucoin.py @@ -0,0 +1,127 @@ +''' +https://github.com/Kucoin/kucoin-universal-sdk/blob/main/sdk/python/README.md +''' + +from credentials import get_api_key + +from kucoin_universal_sdk.api.client import DefaultClient +from kucoin_universal_sdk.model.client_option import ClientOptionBuilder +from kucoin_universal_sdk.model.constants import GLOBAL_API_ENDPOINT, GLOBAL_FUTURES_API_ENDPOINT, GLOBAL_BROKER_API_ENDPOINT +from kucoin_universal_sdk.model.transport_option import TransportOptionBuilder +from kucoin_universal_sdk.generate.earn.earn.model_get_savings_products_req import GetSavingsProductsReqBuilder +from kucoin_universal_sdk.generate.earn.earn.model_get_account_holding_req import GetAccountHoldingReqBuilder +from kucoin_universal_sdk.generate.earn.earn.model_purchase_req import PurchaseReqBuilder +from kucoin_universal_sdk.generate.earn.earn.model_redeem_req import RedeemReqBuilder +from kucoin_universal_sdk.generate.account.account.model_get_spot_account_list_req import GetSpotAccountListReqBuilder + +class kucoin_earn: + def __init__(self): + api_key, api_secret, api_passphrase = get_api_key("kucoin") + + http_transport_option = ( + TransportOptionBuilder() + .set_keep_alive(True) + .set_max_pool_size(10) + .set_max_connection_per_pool(10) + .build() + ) + + client_option = ( + ClientOptionBuilder() + .set_key(api_key) + .set_secret(api_secret) + .set_passphrase(api_passphrase) + .set_spot_endpoint(GLOBAL_API_ENDPOINT) + .set_futures_endpoint(GLOBAL_FUTURES_API_ENDPOINT) + .set_broker_endpoint(GLOBAL_BROKER_API_ENDPOINT) + .set_transport_option(http_transport_option) + .build() + ) + + self.client = DefaultClient(client_option) + kucoin_rest_service = self.client.rest_service() + self.account_api = kucoin_rest_service.get_account_service().get_account_api + self.earn_api = kucoin_rest_service.get_earn_service().get_earn_api + + + def get_trading_balance(self, coin): + ''' + Returns the free available balance of a coin in the trading account (or the equivalent account in the exchange) + ''' + request = GetSpotAccountListReqBuilder().set_currency(coin).set_type("trade").build() + response = self.account_api().get_spot_account_list(request) + balance = response.to_dict()["data"][0]["available"] + return balance + + + def get_available_products(self, coin): + request = GetSavingsProductsReqBuilder().set_currency(coin).build() + response = self.earn_api().get_savings_products(request) + return response.to_dict() + + + def subscribe_product(self, product_id, amount, auto_subscribe=True, source_account="SPOT"): + ''' + source_account: "TRADE" or "MAIN" + auto_subscribe is ignored here + ''' + if source_account.upper() in ["SPOT","TRADE","ALL"]: + source="trade" + elif source_account.upper() in ["FUND","MAIN"]: + 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() + response = self.earn_api().purchase(request) + return response.to_dict() + + + def redeem_product(self, order_id, amount="0", source_account="SPOT"): + ''' + source_account is ignored unless orderID=ETH2: "TRADE" or "MAIN" + auto_subscribe is ignored here + ''' + + if source_account in ["SPOT","TRADE","ALL"]: + source="TRADE" + elif source_account in ["FUND","MAIN"]: + 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 = RedeemReqBuilder(order_id=order_id, amount=str(amount), from_account_type=source).build() + response = self.earn_api().purchase(request) + return response.to_dict() + + + def get_position(self, coin, **kwargs): + request = GetAccountHoldingReqBuilder().set_currency(coin).build() + response = self.earn_api().get_account_holding(request) + return response.to_dict() + + + def get_account(self,coin,**kwargs): + request = GetAccountHoldingReqBuilder().build() + response = self.earn_api().get_account_holding(request) + return response.to_dict() + + def get_personal_left_quota(self, *args, **kwargs): + return {"Error": "N/A"} + + + def get_subscription_record(self, **kwargs): + return {"Error": "N/A"} + + + def get_redemption_record(self, **kwargs): + return {"Error": "N/A"} + + + def get_rewards_history(self, type="ALL", **kwargs): + return {"Error": "N/A"} + + + def get_subscription_preview(self, product_id, amount, **kwargs): + return {"Error": "N/A"} + \ No newline at end of file diff --git a/libraries/wrappers/earn_okx.py b/libraries/wrappers/earn_okx.py new file mode 100644 index 0000000..2c16d6d --- /dev/null +++ b/libraries/wrappers/earn_okx.py @@ -0,0 +1,183 @@ +''' +https://www.okx.com/docs-v5/en/#financial-product-simple-earn-flexible + +https://github.com/okxapi/python-okx/blob/master/okx/Earning.py + +''' + +import okx.Earning as Earning +import okx.Funding as Funding +import okx.Account as Account +from credentials import get_api_key + + +class okx_earn: + def __init__(self): + api_key, api_secret, passphrase = get_api_key("okx") + self.earning_api = Earning.EarningAPI(api_key, api_secret, passphrase, False, "0") + self.funding_api = Funding.FundingAPI(api_key, api_secret, passphrase, False, "0") + self.account_api = Account.AccountAPI(api_key, api_secret, passphrase, False, "0") + + + def get_trading_balance(self, coin): + ''' + Returns the free available balance of a coin in the trading account (or the equivalent account in the exchange) + ''' + balances = self.account_api.get_account_balance() + for item in balances["data"][0]["details"]: + if item["ccy"] == coin: + return item["availBal"] + return 0.0 + + + def get_funding_balance(self, coin): + balances = self.funding_api.get_balances() + for item in balances["data"]: + if item["ccy"] == coin: + return item["availBal"] + return 0.0 + + + def transfer_to_funding(self,coin,amount): + ''' + Transfer funds from the trading account to the funding account + + Response example: + { + "code": "0", + "msg": "", + "data": [ + { + "transId": "754147", + "ccy": "USDT", + "clientId": "", + "from": "6", + "amt": "0.1", + "to": "18" + } + ] + } + ''' + + transfer = self.funding_api.funds_transfer(coin,amount,"18","6","0") + return transfer + + + def transfer_to_trading(self,coin,amount): + ''' + Transfer funds from the funding account to the trading account + + Response example: + { + "code": "0", + "msg": "", + "data": [ + { + "transId": "754147", + "ccy": "USDT", + "clientId": "", + "from": "6", + "amt": "0.1", + "to": "18" + } + ] + } + ''' + transfer = self.funding_api.funds_transfer(coin,amount,"6","18","0") + return transfer + + + def get_transfer_state(self, transaction_id): + ''' + Gets the state of a transfer. + Sometimes the transfer request fails, even if the transfer was successful. + + Sample response: + { + "code": "0", + "data": [ + { + "amt": "1.5", + "ccy": "USDT", + "clientId": "", + "from": "18", + "instId": "", //deprecated + "state": "success", + "subAcct": "test", + "to": "6", + "toInstId": "", //deprecated + "transId": "1", + "type": "1" + } + ], + "msg": "" + } + ''' + transfer = self.funding_api.transfer_state(transaction_id) + return transfer + + + def get_available_products(self, coin): + return self.earning_api.get_public_borrow_info(coin) + + + def subscribe_product(self, coin, amount, rate=None): + ''' + ONLY ASSETS IN THE FUNDING ACCOUNT CAN BE USED FOR SUBSCRIPTION, MOVE THE FUNDS FROM + THE TRADING ACCOUNT TO THE FUNDING ACCOUNT BEFORE SUBSCRIBING. + ''' + if rate is None: + rate = self.get_avg_rate(coin) + return self.earning_api.savings_purchase_redemption(coin, str(amount), "purchase", str(rate)) + + + def redeem_product(self, coin, amount): + ''' + ASSETS REDEEMED WILL BE PLACED IN THE FUNDING ACCOUNT, MOVE THE FUNDS FROM THE FUNDING ACCOUNT + TO THE TRADING ACCOUNT AFTER REDEMPTION. + ''' + return self.earning_api.savings_purchase_redemption(coin, str(amount), "redempt", "0") + + + def set_rate(self, coin, rate): + return self.earning_api.set_lending_rate(coin, str(rate)) + + + def get_avg_rate(self,coin): + ''' + Returns the 24hs average lending rate + ''' + rate = self.earning_api.get_public_borrow_info(coin) + return str(rate["data"][0]["avgRate"]) + + + def get_position(self, coin, **kwargs): + return self.earning_api.get_saving_balance(coin) + + + def get_account(self, coin, recv_window=5000): + return self.earning_api.get_saving_balance() + + + def get_lending_history(self,coin=None): + return self.earning_api.get_lending_history(coin) + + + def get_personal_left_quota(self, product_id, **kwargs): + return None + + + def get_subscription_record(self, **kwargs): + return None + + + def get_redemption_record(self, **kwargs): + return None + + + def get_rewards_history(self, type="ALL", **kwargs): + return None + + + def get_subscription_preview(self, product_id, amount, **kwargs): + return None \ No newline at end of file diff --git a/main.py b/main.py new file mode 100644 index 0000000..14d1613 --- /dev/null +++ b/main.py @@ -0,0 +1,17 @@ +import libraries.balance_accounts as balance_accounts +from libraries.wrappers import earn_binance +from libraries.wrappers import earn_kucoin +from libraries.wrappers import earn_okx +from libraries.wrappers import earn_gateio +import json + +kucoin = earn_kucoin.kucoin_earn() +binance = earn_binance.binance_earn() +okx = earn_okx.okx_earn() +gateio = earn_gateio.gateio_earn() + +if __name__=="__main__": + #Available products + print(okx.get_funding_balance("USDT")) + +