From db859e803f377a1b9a199aa544ceb595e475d75c Mon Sep 17 00:00:00 2001 From: Mark Veidemanis Date: Mon, 7 Feb 2022 13:24:09 +0000 Subject: [PATCH] Improve class passing and refactor --- handler/agora.py | 86 +--------------------------------------- handler/app.py | 70 ++++++++++----------------------- handler/irc.py | 32 ++------------- handler/markets.py | 87 +++++++++++++++++++++++++++++++++++++++++ handler/notify.py | 3 -- handler/revolut.py | 6 --- handler/transactions.py | 12 ------ 7 files changed, 114 insertions(+), 182 deletions(-) create mode 100644 handler/markets.py diff --git a/handler/agora.py b/handler/agora.py index e6a1346..921443a 100644 --- a/handler/agora.py +++ b/handler/agora.py @@ -64,15 +64,6 @@ class Agora(object): # Assets that cheat has been run on self.cheat_run_on = [] - def set_irc(self, irc): - self.irc = irc - - def set_tx(self, tx): - self.tx = tx - - def set_notify(self, notify): - self.notify = notify - def setup_loop(self): """ Set up the LoopingCall to get all active trades and messages. @@ -475,11 +466,11 @@ class Agora(object): continue if xmr: if asset == "XMR": - new_margin = self.autoprice(public_ads, currency) + new_margin = self.markets.autoprice(public_ads, currency) new_formula = f"coingeckoxmrusd*usd{currency.lower()}*{new_margin}" if btc: if asset == "BTC": - new_margin = self.autoprice(public_ads, currency) + new_margin = self.markets.autoprice(public_ads, currency) new_formula = f"coingeckobtcusd*usd{currency.lower()}*{new_margin}" # Get all of our ads our_ads_list = [ad for ad in public_ads if ad[1] == settings.Agora.Username] @@ -556,79 +547,6 @@ class Agora(object): ) self.irc.sendmsg(f"Slow ad update completed with {iterations} iterations: [{', '.join(assets)}] | [{', '.join(currencies)}]") - def autoprice(self, ads, currency): - """ - Helper function to automatically adjust the price up/down in certain markets - in order to gain the most profits and sales. - :param ads: list of ads - :type ads: list of lists - :param currency: currency of the ads - :type currency: string - :return: the rate we should use for this currency - :rtype: float - """ - self.log.debug("Autoprice starting for {x}", x=currency) - # Find cheapest ad - # Filter by 3rd index on each ad list to find the cheapest - min_margin_ad = min(ads, key=lambda x: x[4]) - self.log.debug("Minimum margin ad: {x}", x=min_margin_ad) - - # Find second cheapest that is not us - # Remove results from ads that are us - ads_without_us = [ad for ad in ads if not ad[1] == settings.Agora.Username] - self.log.debug("Ads without us: {x}", x=ads_without_us) - # Find ads above our min that are not us - ads_above_our_min_not_us = [ad for ad in ads_without_us if ad[4] > float(settings.Agora.MinMargin)] - self.log.debug("Ads above our min not us: {x}", x=ads_above_our_min_not_us) - # Check that this list without us is not empty - if ads_without_us: - # Find the cheapest from these - min_margin_ad_not_us = min(ads_without_us, key=lambda x: x[4]) - self.log.debug("Min margin ad not us: {x}", x=min_margin_ad_not_us) - # Lowball the lowest ad that is not ours - lowball_lowest_not_ours = min_margin_ad_not_us[4] # - 0.005 - self.log.debug("Lowball lowest not ours: {x}", x=lowball_lowest_not_ours) - - # Check if the username field of the cheapest ad matches ours - if min_margin_ad[1] == settings.Agora.Username: - self.log.debug("We are the cheapest for: {x}", x=currency) - # We are the cheapest! - # Are all of the ads ours? - all_ads_ours = all([ad[1] == settings.Agora.Username for ad in ads]) - if all_ads_ours: - self.log.debug("All ads are ours for: {x}", x=currency) - # Now we know it's safe to return the maximum value - return float(settings.Agora.MaxMargin) - else: - self.log.debug("All ads are NOT ours for: {x}", x=currency) - # All the ads are not ours, but we are first... - # Check if the lowballed, lowest (that is not ours) ad's margin - # is less than our minimum - if lowball_lowest_not_ours < float(settings.Agora.MinMargin): - self.log.debug("Lowball lowest not ours less than MinMargin") - return float(settings.Agora.MinMargin) - elif lowball_lowest_not_ours > float(settings.Agora.MaxMargin): - self.log.debug("Lowball lowest not ours more than MaxMargin") - return float(settings.Agora.MaxMargin) - else: - self.log.debug("Returning lowballed figure: {x}", x=lowball_lowest_not_ours) - return lowball_lowest_not_ours - else: - self.log.debug("We are NOT the cheapest for: {x}", x=currency) - # We are not the cheapest :( - # Check if this list is empty - if not ads_above_our_min_not_us: - # Return the maximum margin? - return float(settings.Agora.MaxMargin) - # Find cheapest ad above our min that is not us - cheapest_ad = min(ads_above_our_min_not_us, key=lambda x: x[4]) - cheapest_ad_margin = cheapest_ad[4] # - 0.005 - if cheapest_ad_margin > float(settings.Agora.MaxMargin): - self.log.debug("Cheapest ad not ours more than MaxMargin") - return float(settings.Agora.MaxMargin) - self.log.debug("Cheapest ad above our min that is not us: {x}", x=cheapest_ad) - return cheapest_ad_margin - @handle_exceptions def nuke_ads(self): """ diff --git a/handler/app.py b/handler/app.py index cbb643e..717c1f0 100755 --- a/handler/app.py +++ b/handler/app.py @@ -16,6 +16,7 @@ from agora import Agora from transactions import Transactions from irc import bot from notify import Notify +from markets import Markets def convert(data): @@ -38,9 +39,6 @@ class WebApp(object): def __init__(self): self.log = Logger("webapp") - def set_tx(self, tx): - self.tx = tx - @app.route("/callback", methods=["POST"]) def callback(self, request): content = request.content.read() @@ -55,59 +53,33 @@ class WebApp(object): if __name__ == "__main__": - # Define Notify - notify = Notify() + init_map = { + "notify": Notify(), + "irc": bot(), + "agora": Agora(), + "markets": Markets(), + "revolut": Revolut(), + "tx": Transactions(), + "webapp": WebApp(), + } + for classname, object_instance in init_map.items(): + # notify, Notify + for classname_inside, object_instance_inside in init_map.items(): + if not classname == classname_inside: + # irc, bot + setattr(object_instance, classname_inside, object_instance_inside) - # Define IRC and Agora - irc = bot() - agora = Agora() - - # Pass Notify to IRC and Agora - irc.set_notify(notify) - agora.set_notify(notify) - - # Pass Agora to Notify - notify.set_agora(agora) - - # Pass IRC to Agora and Agora to IRC - # This is to prevent recursive dependencies - agora.set_irc(irc) - irc.set_agora(agora) - - # Define Revolut - revolut = Revolut() - # Pass IRC to Revolut and Revolut to IRC - revolut.set_irc(irc) - irc.set_revolut(revolut) - revolut.set_agora(agora) - - # Define Transactions - tx = Transactions() - - # Pass Notify to Transactions - tx.set_notify(notify) - - # Pass Agora and IRC to Transactions and Transactions to IRC - tx.set_agora(agora) - tx.set_irc(irc) - tx.set_revolut(revolut) - irc.set_tx(tx) - agora.set_tx(tx) - - # Define WebApp - webapp = WebApp() - webapp.set_tx(tx) # Handle setting up JWT and request_token from an auth code if settings.Revolut.SetupToken == "1": - deferLater(reactor, 1, revolut.setup_auth) + deferLater(reactor, 1, init_map["revolut"].setup_auth) else: # Schedule refreshing the access token using the refresh token - deferLater(reactor, 1, revolut.get_new_token, True) + deferLater(reactor, 1, init_map["revolut"].get_new_token, True) # Check if the webhook is set up and set up if not - deferLater(reactor, 4, revolut.setup_webhook) + deferLater(reactor, 4, init_map["revolut"].setup_webhook) # Schedule repeatedly refreshing the access token - lc = LoopingCall(revolut.get_new_token) + lc = LoopingCall(init_map["revolut"].get_new_token) lc.start(int(settings.Revolut.RefreshSec)) # Run the WebApp - webapp.app.run("127.0.0.1", 8080) + init_map["webapp"].app.run("127.0.0.1", 8080) diff --git a/handler/irc.py b/handler/irc.py index 57fb208..83d9bb5 100644 --- a/handler/irc.py +++ b/handler/irc.py @@ -38,18 +38,6 @@ class IRCBot(irc.IRCClient): self.channel = settings.IRC.Channel - def set_agora(self, agora): - self.agora = agora - - def set_revolut(self, revolut): - self.revolut = revolut - - def set_tx(self, tx): - self.tx = tx - - def set_notify(self, notify): - self.notify = notify - def parse(self, user, host, channel, msg): """ Simple handler for IRC commands. @@ -185,18 +173,6 @@ class IRCBotFactory(protocol.ClientFactory): def __init__(self): self.log = Logger("irc") - def set_agora(self, agora): - self.agora = agora - - def set_revolut(self, revolut): - self.revolut = revolut - - def set_tx(self, tx): - self.tx = tx - - def set_notify(self, notify): - self.notify = notify - def sendmsg(self, msg): """ Passthrough function to send a message to the channel. @@ -215,10 +191,10 @@ class IRCBotFactory(protocol.ClientFactory): """ prcol = IRCBot(self.log) self.client = prcol - self.client.set_agora(self.agora) - self.client.set_revolut(self.revolut) - self.client.set_tx(self.tx) - self.client.set_notify(self.notify) + setattr(self.client, "agora", self.agora) + setattr(self.client, "revolut", self.revolut) + setattr(self.client, "tx", self.tx) + setattr(self.client, "notify", self.notify) return prcol def clientConnectionLost(self, connector, reason): diff --git a/handler/markets.py b/handler/markets.py new file mode 100644 index 0000000..016da35 --- /dev/null +++ b/handler/markets.py @@ -0,0 +1,87 @@ +# Twisted/Klein imports +from twisted.logger import Logger + +# Project imports +from settings import settings + + +class Markets(object): + """ " + Markets handler for generic market functions. + """ + + def __init__(self): + self.log = Logger("markets") + + def autoprice(self, ads, currency): + """ + Helper function to automatically adjust the price up/down in certain markets + in order to gain the most profits and sales. + :param ads: list of ads + :type ads: list of lists + :param currency: currency of the ads + :type currency: string + :return: the rate we should use for this currency + :rtype: float + """ + self.log.debug("Autoprice starting for {x}", x=currency) + # Find cheapest ad + # Filter by 3rd index on each ad list to find the cheapest + min_margin_ad = min(ads, key=lambda x: x[4]) + self.log.debug("Minimum margin ad: {x}", x=min_margin_ad) + + # Find second cheapest that is not us + # Remove results from ads that are us + ads_without_us = [ad for ad in ads if not ad[1] == settings.Agora.Username] + self.log.debug("Ads without us: {x}", x=ads_without_us) + # Find ads above our min that are not us + ads_above_our_min_not_us = [ad for ad in ads_without_us if ad[4] > float(settings.Agora.MinMargin)] + self.log.debug("Ads above our min not us: {x}", x=ads_above_our_min_not_us) + # Check that this list without us is not empty + if ads_without_us: + # Find the cheapest from these + min_margin_ad_not_us = min(ads_without_us, key=lambda x: x[4]) + self.log.debug("Min margin ad not us: {x}", x=min_margin_ad_not_us) + # Lowball the lowest ad that is not ours + lowball_lowest_not_ours = min_margin_ad_not_us[4] # - 0.005 + self.log.debug("Lowball lowest not ours: {x}", x=lowball_lowest_not_ours) + + # Check if the username field of the cheapest ad matches ours + if min_margin_ad[1] == settings.Agora.Username: + self.log.debug("We are the cheapest for: {x}", x=currency) + # We are the cheapest! + # Are all of the ads ours? + all_ads_ours = all([ad[1] == settings.Agora.Username for ad in ads]) + if all_ads_ours: + self.log.debug("All ads are ours for: {x}", x=currency) + # Now we know it's safe to return the maximum value + return float(settings.Agora.MaxMargin) + else: + self.log.debug("All ads are NOT ours for: {x}", x=currency) + # All the ads are not ours, but we are first... + # Check if the lowballed, lowest (that is not ours) ad's margin + # is less than our minimum + if lowball_lowest_not_ours < float(settings.Agora.MinMargin): + self.log.debug("Lowball lowest not ours less than MinMargin") + return float(settings.Agora.MinMargin) + elif lowball_lowest_not_ours > float(settings.Agora.MaxMargin): + self.log.debug("Lowball lowest not ours more than MaxMargin") + return float(settings.Agora.MaxMargin) + else: + self.log.debug("Returning lowballed figure: {x}", x=lowball_lowest_not_ours) + return lowball_lowest_not_ours + else: + self.log.debug("We are NOT the cheapest for: {x}", x=currency) + # We are not the cheapest :( + # Check if this list is empty + if not ads_above_our_min_not_us: + # Return the maximum margin? + return float(settings.Agora.MaxMargin) + # Find cheapest ad above our min that is not us + cheapest_ad = min(ads_above_our_min_not_us, key=lambda x: x[4]) + cheapest_ad_margin = cheapest_ad[4] # - 0.005 + if cheapest_ad_margin > float(settings.Agora.MaxMargin): + self.log.debug("Cheapest ad not ours more than MaxMargin") + return float(settings.Agora.MaxMargin) + self.log.debug("Cheapest ad above our min that is not us: {x}", x=cheapest_ad) + return cheapest_ad_margin diff --git a/handler/notify.py b/handler/notify.py index 2c1484c..7d1ca91 100644 --- a/handler/notify.py +++ b/handler/notify.py @@ -16,9 +16,6 @@ class Notify(object): def __init__(self): self.log = Logger("notify") - def set_agora(self, agora): - self.agora = agora - def sendmsg(self, msg, title=None, priority=None, tags=None): headers = {"Title": "Bot"} if title: diff --git a/handler/revolut.py b/handler/revolut.py index 6233fb7..4e138b5 100644 --- a/handler/revolut.py +++ b/handler/revolut.py @@ -28,12 +28,6 @@ class Revolut(object): self.log = Logger("revolut") self.token = None - def set_irc(self, irc): - self.irc = irc - - def set_agora(self, agora): - self.agora = agora - def setup_auth(self): """ Function to create a new Java Web Token and use it to get a refresh/access token. diff --git a/handler/transactions.py b/handler/transactions.py index 7c51c3a..eac6d44 100644 --- a/handler/transactions.py +++ b/handler/transactions.py @@ -24,18 +24,6 @@ class Transactions(object): """ self.log = Logger("transactions") - def set_agora(self, agora): - self.agora = agora - - def set_irc(self, irc): - self.irc = irc - - def set_revolut(self, revolut): - self.revolut = revolut - - def set_notify(self, notify): - self.notify = notify - def transaction(self, data): """ Store details of transaction and post notifications to IRC.