248 lines
11 KiB
Python
248 lines
11 KiB
Python
import time
|
|
import datetime
|
|
from libraries.balance_accounts import balance_accounts
|
|
from libraries.colors import colors
|
|
from decimal import Decimal, getcontext, ROUND_DOWN
|
|
|
|
|
|
class earner:
|
|
def __init__(self, connector, config):
|
|
self.connector = connector
|
|
self.currency = config["currency"]
|
|
self.minimum_amount_in_trading_account = config["minimum_amount_in_trading_account"]
|
|
self.step_size = config["step_size"]
|
|
self.percentage = config["percentage"]
|
|
self.time_between_subscriptions = config["time_between_subscriptions"]
|
|
self.time_between_redemptions = config["time_between_redemptions"]
|
|
|
|
self.last_subscription_time = 0
|
|
self.last_redemption_time = 0
|
|
self.start_time = time.time()
|
|
|
|
self.trading_balance = 0
|
|
self.earning_balance = 0
|
|
|
|
self.is_paused = False
|
|
|
|
self.status_string = ""
|
|
|
|
getcontext().prec = 8
|
|
getcontext().rounding = ROUND_DOWN
|
|
|
|
|
|
def __str__(self):
|
|
return str(self.connector)
|
|
|
|
def write_to_log(self,message):
|
|
with open("earn.log", "a") as f:
|
|
f.write(str(self.connector) + datetime.datetime.now().strftime(' [%Y/%m/%d %H:%M:%S] ') + message + "\n")
|
|
|
|
def toggle_pause(self):
|
|
self.is_paused = not self.is_paused
|
|
return self.is_paused
|
|
|
|
def get_is_paused(self):
|
|
return self.is_paused
|
|
|
|
def set_step_size(self, step_size):
|
|
try:
|
|
self.step_size = float(step_size)
|
|
return self.step_size
|
|
except Exception as e:
|
|
print(e)
|
|
self.write_to_log(str(e))
|
|
return 0
|
|
|
|
def get_step_size(self):
|
|
return self.step_size
|
|
|
|
def set_percentage(self, percentage):
|
|
try:
|
|
self.percentage = float(percentage)
|
|
return self.percentage
|
|
except Exception as e:
|
|
print(e)
|
|
self.write_to_log(str(e))
|
|
return 0
|
|
|
|
def get_percentage(self):
|
|
return self.percentage
|
|
|
|
def set_minimum_amount_in_trading_account(self, minimum_amount_in_trading_account):
|
|
try:
|
|
self.minimum_amount_in_trading_account = float(minimum_amount_in_trading_account)
|
|
return self.minimum_amount_in_trading_account
|
|
except Exception as e:
|
|
print(e)
|
|
self.write_to_log(str(e))
|
|
return 0
|
|
|
|
def get_minimum_amount_in_trading_account(self):
|
|
return self.minimum_amount_in_trading_account
|
|
|
|
def set_time_between_subscriptions(self, time_between_subscriptions):
|
|
try:
|
|
self.time_between_subscriptions = float(time_between_subscriptions)
|
|
return self.time_between_subscriptions
|
|
except Exception as e:
|
|
print(e)
|
|
self.write_to_log(str(e))
|
|
return 0
|
|
|
|
def get_time_between_subscriptions(self):
|
|
return self.time_between_subscriptions
|
|
|
|
def set_time_between_redemptions(self, time_between_redemptions):
|
|
try:
|
|
self.time_between_redemptions = float(time_between_redemptions)
|
|
return self.time_between_redemptions
|
|
except Exception as e:
|
|
print(e)
|
|
self.write_to_log(str(e))
|
|
return 0
|
|
|
|
def get_time_between_redemptions(self):
|
|
return self.time_between_redemptions
|
|
|
|
def get_last_subscription(self):
|
|
return {str(self.connector): self.last_subscription_time}
|
|
|
|
def get_last_redemption(self):
|
|
return {str(self.connector): self.last_redemption_time}
|
|
|
|
def get_status_string(self):
|
|
return self.status_string
|
|
|
|
def get_trading_balance(self):
|
|
return float(self.trading_balance)
|
|
|
|
def get_earning_balance(self):
|
|
return float(self.earning_balance)
|
|
|
|
|
|
def subscribe(self,amount):
|
|
print(f"{datetime.datetime.now().strftime('[%Y/%m/%d %H:%M:%S]')} | {str(self.connector).upper()} | Subscribing {amount} {self.currency}")
|
|
self.write_to_log(f"Subscribing {amount} {self.currency}")
|
|
available_product = self.connector.get_available_products(self.currency)
|
|
subscription = {}
|
|
if available_product["coin"]==self.currency:
|
|
#Every exchange has it own subscription method
|
|
if str(self.connector) in ["binance","kucoin"]:
|
|
subscription = self.connector.subscribe_product(available_product["product_id"],amount)
|
|
elif str(self.connector)=="gateio":
|
|
min_rate = self.connector.get_min_rate(available_product["coin"])["min_rate"]
|
|
time.sleep(.5) #For the sake of the API
|
|
subscription = self.connector.subscribe_product(available_product["product_id"],amount,min_rate)
|
|
elif str(self.connector)=="okx":
|
|
transfer = self.connector.transfer_to_funding(available_product["coin"],str(amount))
|
|
if "Success" in transfer:
|
|
transfer_state = self.connector.get_transfer_state(transfer["transId"])
|
|
if "Success" in transfer_state:
|
|
subscription = self.connector.subscribe_product(available_product["product_id"],amount)
|
|
else:
|
|
print(f"{str(self.connector)} - Transfer of funds state query failed!")
|
|
self.write_to_log("Transfer of funds state query failed! - " + str(subscription))
|
|
return 1
|
|
else:
|
|
print(f"{str(self.connector)} - Transfer of funds failed!")
|
|
self.write_to_log("Transfer of funds failed! - " + str(transfer))
|
|
return 1
|
|
if "Success" in subscription:
|
|
self.last_subscription_time = time.time()
|
|
return 0
|
|
self.write_to_log("Subscription failed! - " + str(subscription))
|
|
return 1
|
|
|
|
|
|
def redeem(self,amount):
|
|
print(f"{datetime.datetime.now().strftime('[%Y/%m/%d %H:%M:%S]')} | {str(self.connector).upper()} | Redeeming {amount} {self.currency}")
|
|
self.write_to_log(f"Redeeming {amount} {self.currency}")
|
|
available_product = self.connector.get_available_products(self.currency)
|
|
redemption = {}
|
|
if available_product["coin"]==self.currency:
|
|
if str(self.connector) in ["binance","gateio"]:
|
|
redemption = self.connector.redeem_product(available_product["product_id"],amount=amount)
|
|
elif str(self.connector)=="kucoin":
|
|
position = self.connector.get_position(self.currency)
|
|
if "Error" not in position:
|
|
redemption = self.connector.redeem_product(position["positionId"],amount=amount)
|
|
else:
|
|
print(f"{str(self.connector)} - Position not found!")
|
|
self.write_to_log("Position not found! " + str(position))
|
|
return 1
|
|
elif str(self.connector)=="okx":
|
|
redemption_step = self.connector.redeem_product(self.currency, amount=amount)
|
|
if "Success" in redemption_step:
|
|
time.sleep(1) #Breathing room
|
|
funding_balance = self.connector.get_funding_balance(self.currency)
|
|
transfer_step = self.connector.transfer_to_trading(self.currency, funding_balance[self.currency])
|
|
if "Success" in transfer_step:
|
|
redemption = self.connector.get_transfer_state(transfer_step["transId"])
|
|
else:
|
|
print(f"{str(self.connector)} - Transfer step failed!")
|
|
self.write_to_log("Transfer step failed! " + str(transfer_step))
|
|
return 1
|
|
else:
|
|
print(f"{str(self.connector)} - Redemption step failed!")
|
|
self.write_to_log("Redemption step failed! " + str(redemption_step))
|
|
return 1
|
|
if "Success" in redemption:
|
|
self.last_redemption_time = time.time()
|
|
return 0
|
|
self.write_to_log("Redemption failed! - " + str(redemption))
|
|
return 1
|
|
|
|
|
|
def run(self):
|
|
'''
|
|
1. Get trading and earning balances
|
|
2. Call balance_accounts
|
|
3. If there are differences:
|
|
a. If subscribe side, subscribe if time_since_last_subscription>time_between_subscriptions
|
|
b. If redeem side, redeem if time_since_last_redeem>time_between_redemptions
|
|
4. Output status to status_string
|
|
'''
|
|
|
|
#Get trading and earning balances
|
|
trading_balance_dict = self.connector.get_trading_balance(self.currency)
|
|
if "Error" not in trading_balance_dict:
|
|
self.trading_balance = trading_balance_dict[self.currency]
|
|
else:
|
|
self.trading_balance = None
|
|
|
|
earning_balance_dict = self.connector.get_position(self.currency)
|
|
if earning_balance_dict=={}:
|
|
self.earning_balance = 0
|
|
elif "Error" not in earning_balance_dict:
|
|
self.earning_balance = earning_balance_dict["amount"]
|
|
else:
|
|
self.earning_balance = None
|
|
|
|
paused_string = ""
|
|
if not self.is_paused:
|
|
target_trading_amount, target_earning_amount = balance_accounts(Decimal(self.trading_balance),
|
|
Decimal(self.earning_balance),
|
|
Decimal(self.minimum_amount_in_trading_account),
|
|
Decimal(self.step_size),
|
|
Decimal(self.percentage))
|
|
earning_delta = Decimal(0)
|
|
if self.earning_balance is None:
|
|
print(f"{str(self.connector).upper()} - There was an error fetching earning balance")
|
|
else:
|
|
if float(self.earning_balance)!=0:
|
|
earning_delta = target_earning_amount - Decimal(self.earning_balance)
|
|
if earning_delta>Decimal(self.step_size) and time.time()-self.last_subscription_time>self.time_between_subscriptions:
|
|
self.subscribe(earning_delta)
|
|
if earning_delta<-Decimal(self.step_size) and time.time()-self.last_redemption_time>self.time_between_redemptions:
|
|
self.redeem(-earning_delta)
|
|
#print(f"{str(self.connector)} - Difference: {earning_delta}")
|
|
else:
|
|
paused_string = "| "+colors.yellow+"PAUSED"+colors.white
|
|
|
|
#Output status to status_string
|
|
balances_string = f"Trading balance: {float(self.trading_balance):.2f} {self.currency} | Earning balance: {float(self.earning_balance):.2f} {self.currency}"
|
|
total_balance = float(self.earning_balance)+float(self.trading_balance)
|
|
percentages_string = f"On earn: {float(self.earning_balance)/total_balance:.2%} {paused_string}"
|
|
|
|
self.status_string = f"{colors.cyan}{str(self).upper()}{colors.white} | {balances_string} | {percentages_string}"
|
|
|