Finish implementation and tests for the cheat system
This commit is contained in:
parent
a8fdc49281
commit
7d101cb02d
125
handler/agora.py
125
handler/agora.py
|
@ -386,14 +386,15 @@ class Agora(object):
|
||||||
for ad in ads:
|
for ad in ads:
|
||||||
price = float(ad[2])
|
price = float(ad[2])
|
||||||
rate = round(price / base_currency_price, 2)
|
rate = round(price / base_currency_price, 2)
|
||||||
|
ad.append(asset)
|
||||||
ad.append(rate)
|
ad.append(rate)
|
||||||
return sorted(ads, key=lambda x: x[2])
|
return sorted(ads, key=lambda x: x[2])
|
||||||
|
|
||||||
def _update_prices(self, xmr=None, btc=None):
|
def run_cheat_in_thread(self, assets=None):
|
||||||
"""
|
"""
|
||||||
Update prices in another thread.
|
Update prices in another thread.
|
||||||
"""
|
"""
|
||||||
if xmr is None and btc is None:
|
if not assets:
|
||||||
all_assets = loads(settings.Agora.AssetList)
|
all_assets = loads(settings.Agora.AssetList)
|
||||||
assets_not_run = set(all_assets) ^ set(self.cheat_run_on)
|
assets_not_run = set(all_assets) ^ set(self.cheat_run_on)
|
||||||
if not assets_not_run:
|
if not assets_not_run:
|
||||||
|
@ -403,16 +404,22 @@ class Agora(object):
|
||||||
else:
|
else:
|
||||||
asset = assets_not_run.pop()
|
asset = assets_not_run.pop()
|
||||||
self.cheat_run_on.append(asset)
|
self.cheat_run_on.append(asset)
|
||||||
if asset == "XMR":
|
deferToThread(self.update_prices, [asset])
|
||||||
deferToThread(self.update_prices, True, False) # XMR, BTC
|
|
||||||
elif asset == "BTC":
|
|
||||||
deferToThread(self.update_prices, False, True) # XMR, BTC
|
|
||||||
return asset
|
return asset
|
||||||
else:
|
else:
|
||||||
deferToThread(self.update_prices, xmr, btc)
|
deferToThread(self.update_prices, assets)
|
||||||
|
|
||||||
@handle_exceptions
|
@handle_exceptions
|
||||||
def get_all_public_ads(self):
|
def update_prices(self, assets=None):
|
||||||
|
# Get all public ads for the given assets
|
||||||
|
public_ads = self.get_all_public_ads(assets)
|
||||||
|
|
||||||
|
# Get the ads to update
|
||||||
|
to_update = self.markets.get_new_ad_equations(public_ads, assets)
|
||||||
|
self.slow_ad_update(to_update)
|
||||||
|
|
||||||
|
@handle_exceptions
|
||||||
|
def get_all_public_ads(self, assets=None):
|
||||||
"""
|
"""
|
||||||
Get all public ads for our listed currencies.
|
Get all public ads for our listed currencies.
|
||||||
:return: dict of public ads keyed by currency
|
:return: dict of public ads keyed by currency
|
||||||
|
@ -424,13 +431,15 @@ class Agora(object):
|
||||||
"BTC": "bitcoin",
|
"BTC": "bitcoin",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if not assets:
|
||||||
|
assets = self.markets.get_all_assets()
|
||||||
# Get all currencies we have ads for, deduplicated
|
# Get all currencies we have ads for, deduplicated
|
||||||
currencies = list(set([x[0] for x in loads(settings.Agora.DistList)]))
|
currencies = self.markets.get_all_currencies()
|
||||||
providers = loads(settings.Agora.ProviderList)
|
providers = self.markets.get_all_providers()
|
||||||
# We want to get the ads for each of these currencies and return the result
|
# We want to get the ads for each of these currencies and return the result
|
||||||
|
|
||||||
for asset in loads(settings.Agora.AssetList):
|
rates_crypto = self.cg.get_price(ids=["monero", "bitcoin"], vs_currencies=currencies)
|
||||||
rates_crypto = self.cg.get_price(ids=["monero", "bitcoin"], vs_currencies=currencies)
|
for asset in assets:
|
||||||
for currency in currencies:
|
for currency in currencies:
|
||||||
cg_asset_name = crypto_map[asset]
|
cg_asset_name = crypto_map[asset]
|
||||||
try:
|
try:
|
||||||
|
@ -442,99 +451,13 @@ class Agora(object):
|
||||||
if not ads:
|
if not ads:
|
||||||
continue
|
continue
|
||||||
if currency in public_ads:
|
if currency in public_ads:
|
||||||
for ad in list(ads): # Copy the list so we don't mutate and get stuck in an infinite loop
|
for ad in list(ads):
|
||||||
public_ads[currency].append(ad)
|
if ad not in public_ads[currency]:
|
||||||
|
public_ads[currency].append(ad)
|
||||||
else:
|
else:
|
||||||
public_ads[currency] = ads
|
public_ads[currency] = ads
|
||||||
|
|
||||||
return public_ads
|
return public_ads
|
||||||
|
|
||||||
@handle_exceptions
|
|
||||||
def update_prices(self, xmr=True, btc=True):
|
|
||||||
if xmr and btc:
|
|
||||||
our_ads = self.enum_ads()
|
|
||||||
elif xmr and not btc:
|
|
||||||
our_ads = self.enum_ads("XMR")
|
|
||||||
elif not xmr and btc:
|
|
||||||
our_ads = self.enum_ads("BTC")
|
|
||||||
|
|
||||||
self.log.debug("Our ads: {ads}", ads=our_ads)
|
|
||||||
to_update = []
|
|
||||||
if our_ads is None:
|
|
||||||
return False
|
|
||||||
if our_ads is False:
|
|
||||||
return False
|
|
||||||
currencies = [x[3].lower() for x in our_ads]
|
|
||||||
# Sets deduplicate by default
|
|
||||||
providers = list(set([x[4] for x in our_ads]))
|
|
||||||
public_ad_dict_xmr = {}
|
|
||||||
public_ad_dict_btc = {}
|
|
||||||
rates_crypto = self.cg.get_price(ids=["monero", "bitcoin"], vs_currencies=currencies)
|
|
||||||
|
|
||||||
# NOTES:
|
|
||||||
# Get all ads for each currency, with all the payment methods.
|
|
||||||
# Create a function to, in turn, filter these so it contains only one payment method. Run autoprice on this.
|
|
||||||
# Append all results to to_update. Repeat for remaining payment methods, then call slow update.
|
|
||||||
|
|
||||||
for currency in currencies:
|
|
||||||
try:
|
|
||||||
rates_xmr = rates_crypto["monero"][currency]
|
|
||||||
rates_btc = rates_crypto["bitcoin"][currency]
|
|
||||||
if xmr:
|
|
||||||
public_ad_dict_xmr[currency] = self.wrap_public_ads("XMR", currency, providers=providers, rates=rates_xmr)
|
|
||||||
if public_ad_dict_xmr[currency] is False:
|
|
||||||
return False
|
|
||||||
if btc:
|
|
||||||
public_ad_dict_btc[currency] = self.wrap_public_ads("BTC", currency, providers=providers, rates=rates_btc)
|
|
||||||
if public_ad_dict_btc[currency] is False:
|
|
||||||
return False
|
|
||||||
except KeyError:
|
|
||||||
self.log.error("Error getting public ads for currency {currency}", currency=currency)
|
|
||||||
continue
|
|
||||||
for asset, ad_id, country, currency, provider in our_ads:
|
|
||||||
# Get the ads for this country/currency pair
|
|
||||||
try:
|
|
||||||
if asset == "XMR":
|
|
||||||
public_ads = public_ad_dict_xmr[currency.lower()]
|
|
||||||
elif asset == "BTC":
|
|
||||||
public_ads = public_ad_dict_btc[currency.lower()]
|
|
||||||
except KeyError:
|
|
||||||
continue
|
|
||||||
if not public_ads:
|
|
||||||
continue
|
|
||||||
if xmr:
|
|
||||||
if asset == "XMR":
|
|
||||||
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.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]
|
|
||||||
if not len(our_ads_list) == 1:
|
|
||||||
if not len(set([x[3] for x in our_ads_list])) == 1:
|
|
||||||
self.log.error("Our ads have different margins: {ads}", ads=our_ads_list)
|
|
||||||
# Get one from the list, they're probably the same, if not we will deal with the other
|
|
||||||
# ones in a later pass
|
|
||||||
|
|
||||||
# Get one
|
|
||||||
our_ad = our_ads_list.pop()
|
|
||||||
|
|
||||||
# Take the 4th argument, the margin
|
|
||||||
our_margin = our_ad[3]
|
|
||||||
|
|
||||||
# Don't waste API rate limits on setting the same margin as before
|
|
||||||
if new_margin != our_margin:
|
|
||||||
# rtrn = self.agora.ad_equation(ad_id, new_formula)
|
|
||||||
to_update.append([ad_id, new_formula, asset, currency, False])
|
|
||||||
# if not rtrn["success"]:
|
|
||||||
# self.log.error("Error updating ad {ad_id}: {response}", ad_id=ad_id, response=rtrn["response"])
|
|
||||||
self.log.info("Rate for {currency}: {margin}", currency=currency, margin=new_margin)
|
|
||||||
else:
|
|
||||||
self.log.info("Not changed rate for {currency}, keeping old margin of {margin}", currency=currency, margin=our_margin)
|
|
||||||
self.slow_ad_update(to_update)
|
|
||||||
|
|
||||||
def slow_ad_update(self, ads):
|
def slow_ad_update(self, ads):
|
||||||
"""
|
"""
|
||||||
Slow ad equation update utilising exponential backoff in order to guarantee all ads are updated.
|
Slow ad equation update utilising exponential backoff in order to guarantee all ads are updated.
|
||||||
|
|
|
@ -353,20 +353,14 @@ class IRCCommands(object):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def run(cmd, spl, length, authed, msg, agora, revolut, tx, notify):
|
def run(cmd, spl, length, authed, msg, agora, revolut, tx, notify):
|
||||||
if length == 1:
|
if length == 1:
|
||||||
agora._update_prices()
|
agora.run_cheat_in_thread()
|
||||||
msg("Running cheat in thread.")
|
msg("Running cheat in thread.")
|
||||||
elif length == 2:
|
elif length == 2:
|
||||||
asset = spl[1]
|
asset = spl[1]
|
||||||
if asset not in loads(settings.Agora.AssetList):
|
if asset not in loads(settings.Agora.AssetList):
|
||||||
msg(f"Not a valid asset: {spl[1]}")
|
msg(f"Not a valid asset: {spl[1]}")
|
||||||
return
|
return
|
||||||
if asset == "XMR":
|
agora.run_cheat_in_thread([asset])
|
||||||
xmr = True
|
|
||||||
btc = False
|
|
||||||
elif asset == "BTC":
|
|
||||||
xmr = False
|
|
||||||
btc = True
|
|
||||||
agora._update_prices(xmr=xmr, btc=btc)
|
|
||||||
msg(f"Running cheat in thread for {asset}.")
|
msg(f"Running cheat in thread for {asset}.")
|
||||||
|
|
||||||
class cheatnext(object):
|
class cheatnext(object):
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
# Twisted/Klein imports
|
# Twisted/Klein imports
|
||||||
from twisted.logger import Logger
|
from twisted.logger import Logger
|
||||||
|
|
||||||
|
# Other library imports
|
||||||
|
from json import loads
|
||||||
|
|
||||||
# Project imports
|
# Project imports
|
||||||
from settings import settings
|
from settings import settings
|
||||||
|
|
||||||
|
@ -13,6 +16,68 @@ class Markets(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.log = Logger("markets")
|
self.log = Logger("markets")
|
||||||
|
|
||||||
|
def get_all_assets(self):
|
||||||
|
assets = loads(settings.Agora.AssetList)
|
||||||
|
return assets
|
||||||
|
|
||||||
|
def get_all_providers(self):
|
||||||
|
providers = loads(settings.Agora.ProviderList)
|
||||||
|
return providers
|
||||||
|
|
||||||
|
def get_all_currencies(self):
|
||||||
|
currencies = list(set([x[0] for x in loads(settings.Agora.DistList)]))
|
||||||
|
return currencies
|
||||||
|
|
||||||
|
def get_new_ad_equations(self, public_ads, assets=None):
|
||||||
|
"""
|
||||||
|
Update all our prices.
|
||||||
|
:param public_ads: dictionary of public ads keyed by currency
|
||||||
|
:type public_ads: dict
|
||||||
|
:return: list of ads to modify
|
||||||
|
:rtype: list
|
||||||
|
"""
|
||||||
|
to_update = []
|
||||||
|
|
||||||
|
# NOTES:
|
||||||
|
# Get all ads for each currency, with all the payment methods.
|
||||||
|
# Create a function to, in turn, filter these so it contains only one payment method. Run autoprice on this.
|
||||||
|
# Append all results to to_update. Repeat for remaining payment methods, then call slow update.
|
||||||
|
|
||||||
|
# (asset, currency, provider)
|
||||||
|
if not assets:
|
||||||
|
assets = self.get_all_assets()
|
||||||
|
currencies = self.get_all_currencies()
|
||||||
|
providers = self.get_all_providers()
|
||||||
|
|
||||||
|
brute = [(asset, currency, provider) for asset in assets for currency in currencies for provider in providers]
|
||||||
|
for asset, currency, provider in brute:
|
||||||
|
# Filter currency
|
||||||
|
try:
|
||||||
|
public_ads_currency = public_ads[currency]
|
||||||
|
except KeyError:
|
||||||
|
self.log.error("Error getting public ads for currency {currency}", currency=currency)
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Filter asset
|
||||||
|
public_ads_filtered = [ad for ad in public_ads_currency if ad[4] == asset]
|
||||||
|
|
||||||
|
# Filter provider
|
||||||
|
public_ads_filtered = [ad for ad in public_ads_filtered if ad[3] == provider]
|
||||||
|
|
||||||
|
our_ads = [ad for ad in public_ads_filtered if ad[1] == settings.Agora.Username]
|
||||||
|
if not our_ads:
|
||||||
|
continue
|
||||||
|
new_margin = self.autoprice(public_ads_filtered, currency)
|
||||||
|
new_formula = f"coingecko{asset.lower()}usd*usd{currency.lower()}*{new_margin}"
|
||||||
|
for ad in our_ads:
|
||||||
|
ad_id = ad[0]
|
||||||
|
asset = ad[4]
|
||||||
|
our_margin = ad[5]
|
||||||
|
if new_margin != our_margin:
|
||||||
|
to_update.append([ad_id, new_formula, asset, currency, False])
|
||||||
|
|
||||||
|
return to_update
|
||||||
|
|
||||||
def autoprice(self, ads, currency):
|
def autoprice(self, ads, currency):
|
||||||
"""
|
"""
|
||||||
Helper function to automatically adjust the price up/down in certain markets
|
Helper function to automatically adjust the price up/down in certain markets
|
||||||
|
@ -27,7 +92,7 @@ class Markets(object):
|
||||||
self.log.debug("Autoprice starting for {x}", x=currency)
|
self.log.debug("Autoprice starting for {x}", x=currency)
|
||||||
# Find cheapest ad
|
# Find cheapest ad
|
||||||
# Filter by 3rd index on each ad list to find the cheapest
|
# Filter by 3rd index on each ad list to find the cheapest
|
||||||
min_margin_ad = min(ads, key=lambda x: x[4])
|
min_margin_ad = min(ads, key=lambda x: x[5])
|
||||||
self.log.debug("Minimum margin ad: {x}", x=min_margin_ad)
|
self.log.debug("Minimum margin ad: {x}", x=min_margin_ad)
|
||||||
|
|
||||||
# Find second cheapest that is not us
|
# Find second cheapest that is not us
|
||||||
|
@ -35,15 +100,15 @@ class Markets(object):
|
||||||
ads_without_us = [ad for ad in ads if not ad[1] == settings.Agora.Username]
|
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)
|
self.log.debug("Ads without us: {x}", x=ads_without_us)
|
||||||
# Find ads above our min that are not 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)]
|
ads_above_our_min_not_us = [ad for ad in ads_without_us if ad[5] > float(settings.Agora.MinMargin)]
|
||||||
self.log.debug("Ads above our min not us: {x}", x=ads_above_our_min_not_us)
|
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
|
# Check that this list without us is not empty
|
||||||
if ads_without_us:
|
if ads_without_us:
|
||||||
# Find the cheapest from these
|
# Find the cheapest from these
|
||||||
min_margin_ad_not_us = min(ads_without_us, key=lambda x: x[4])
|
min_margin_ad_not_us = min(ads_without_us, key=lambda x: x[5])
|
||||||
self.log.debug("Min margin ad not us: {x}", x=min_margin_ad_not_us)
|
self.log.debug("Min margin ad not us: {x}", x=min_margin_ad_not_us)
|
||||||
# Lowball the lowest ad that is not ours
|
# Lowball the lowest ad that is not ours
|
||||||
lowball_lowest_not_ours = min_margin_ad_not_us[4] # - 0.005
|
lowball_lowest_not_ours = min_margin_ad_not_us[5] # - 0.005
|
||||||
self.log.debug("Lowball lowest not ours: {x}", x=lowball_lowest_not_ours)
|
self.log.debug("Lowball lowest not ours: {x}", x=lowball_lowest_not_ours)
|
||||||
|
|
||||||
# Check if the username field of the cheapest ad matches ours
|
# Check if the username field of the cheapest ad matches ours
|
||||||
|
@ -79,7 +144,7 @@ class Markets(object):
|
||||||
return float(settings.Agora.MaxMargin)
|
return float(settings.Agora.MaxMargin)
|
||||||
# Find cheapest ad above our min that is not us
|
# 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 = min(ads_above_our_min_not_us, key=lambda x: x[4])
|
||||||
cheapest_ad_margin = cheapest_ad[4] # - 0.005
|
cheapest_ad_margin = cheapest_ad[5] # - 0.005
|
||||||
if cheapest_ad_margin > float(settings.Agora.MaxMargin):
|
if cheapest_ad_margin > float(settings.Agora.MaxMargin):
|
||||||
self.log.debug("Cheapest ad not ours more than MaxMargin")
|
self.log.debug("Cheapest ad not ours more than MaxMargin")
|
||||||
return float(settings.Agora.MaxMargin)
|
return float(settings.Agora.MaxMargin)
|
||||||
|
|
|
@ -1,63 +1,69 @@
|
||||||
fake_public_ads = {
|
fake_public_ads = {
|
||||||
"NOK": [
|
"JPY": [["b048bad8-3aaa-4727-88ba-d83aaa1727b6", "topmonero", "26978.66", "REVOLUT", "XMR", 1.32]],
|
||||||
["9c3d9fb6-c74c-4a35-bd9f-b6c74c7a3504", "topmonero", "2023.02", "REVOLUT", 1.3],
|
"DKK": [["ef1455dc-4629-4827-9455-dc46291827f0", "topmonero", "1521.50", "REVOLUT", "XMR", 1.32]],
|
||||||
["9c3d9fb6-c74c-4a35-bd9f-b6c74c7a3504", "topmonero", "2023.02", "REVOLUT", 1.3],
|
"CHF": [["fb04a8e2-3c69-45f3-84a8-e23c6975f380", "topmonero", "215.74", "REVOLUT", "XMR", 1.32]],
|
||||||
|
"SEK": [
|
||||||
|
["f0e840b9-29ab-4a6f-a840-b929ab7a6fde", "topmonero", "2053.68", "REVOLUT", "XMR", 1.27],
|
||||||
|
["2252a3f7-6d6b-400b-92a3-f76d6bb00b50", "SwishaMonero", "2053.68", "REVOLUT", "XMR", 1.27],
|
||||||
],
|
],
|
||||||
|
"CZK": [["80aa52ef-a5d3-462c-aa52-efa5d3862cbe", "topmonero", "4960.76", "REVOLUT", "XMR", 1.32]],
|
||||||
|
"PLN": [["b5be2881-4491-4a60-be28-814491ca606a", "topmonero", "926.48", "REVOLUT", "XMR", 1.32]],
|
||||||
"EUR": [
|
"EUR": [
|
||||||
["65b452e3-a29f-4233-b452-e3a29fe23369", "topmonero", "184.28", "REVOLUT", 1.19],
|
["87af6467-be02-476e-af64-67be02676e9a", "topmonero", "187.11", "REVOLUT", "XMR", 1.21],
|
||||||
["65b452e3-a29f-4233-b452-e3a29fe23369", "topmonero", "184.28", "REVOLUT", 1.19],
|
["57e3e8d6-45fe-40da-a3e8-d645fe20da46", "SecureMole", "187.11", "REVOLUT", "XMR", 1.21],
|
||||||
["87af6467-be02-476e-af64-67be02676e9a", "topmonero", "184.28", "REVOLUT", 1.19],
|
["d2c6645c-6d56-4094-8664-5c6d5640941b", "topmonero", "187.11", "REVOLUT", "XMR", 1.21],
|
||||||
["d2c6645c-6d56-4094-8664-5c6d5640941b", "topmonero", "184.28", "REVOLUT", 1.19],
|
["65b452e3-a29f-4233-b452-e3a29fe23369", "topmonero", "187.11", "REVOLUT", "XMR", 1.21],
|
||||||
["65b452e3-a29f-4233-b452-e3a29fe23369", "topmonero", "184.28", "REVOLUT", 1.19],
|
],
|
||||||
["65b452e3-a29f-4233-b452-e3a29fe23369", "topmonero", "184.28", "REVOLUT", 1.19],
|
"NOK": [["9c3d9fb6-c74c-4a35-bd9f-b6c74c7a3504", "topmonero", "2058.76", "REVOLUT", "XMR", 1.32]],
|
||||||
["87af6467-be02-476e-af64-67be02676e9a", "topmonero", "184.28", "REVOLUT", 1.19],
|
"THB": [["9a7bd726-6229-4fda-bbd7-2662295fda98", "topmonero", "7668.74", "REVOLUT", "XMR", 1.31]],
|
||||||
["d2c6645c-6d56-4094-8664-5c6d5640941b", "topmonero", "184.28", "REVOLUT", 1.19],
|
"ZAR": [["92877e53-823e-4ac5-877e-53823e2ac545", "topmonero", "3583.09", "REVOLUT", "XMR", 1.3]],
|
||||||
|
"MXN": [["bf12756b-0138-49ca-9275-6b0138f9caf1", "topmonero", "4815.61", "REVOLUT", "XMR", 1.31]],
|
||||||
|
"TRY": [["3c5068ce-fcf9-40cc-9068-cefcf920cc02", "topmonero", "3166.12", "REVOLUT", "XMR", 1.31]],
|
||||||
|
"RUB": [["24a9cad1-0bce-46f3-a9ca-d10bce86f34f", "topmonero", "17513.23", "REVOLUT", "XMR", 1.31]],
|
||||||
|
"SGD": [["ac9eb9c8-88c7-4add-9eb9-c888c72addb2", "topmonero", "313.83", "REVOLUT", "XMR", 1.32]],
|
||||||
|
"HKD": [["b23aa3b3-4c91-42e4-baa3-b34c9162e4e0", "topmonero", "1818.76", "REVOLUT", "XMR", 1.32]],
|
||||||
|
"AUD": [["68b50d95-91d2-4f21-b50d-9591d22f218d", "topmonero", "327.16", "REVOLUT", "XMR", 1.31]],
|
||||||
|
"HUF": [["f886768f-b9c9-4cf7-8676-8fb9c9ccf7ee", "topmonero", "72350.54", "REVOLUT", "XMR", 1.32]],
|
||||||
|
"USD": [
|
||||||
|
["24871dd9-54e8-4962-871d-d954e82962b1", "topmonero", "224.36", "REVOLUT", "XMR", 1.27],
|
||||||
|
["b5f80385-73cb-4f98-b803-8573cb6f9846", "SecureMole", "224.36", "REVOLUT", "XMR", 1.27],
|
||||||
|
["92add2b6-ccd5-4351-add2-b6ccd53351e4", "topmonero", "224.36", "REVOLUT", "XMR", 1.27],
|
||||||
|
["04be2471-72a5-4ab6-be24-7172a57ab64a", "EmmanuelMuema", "232.98", "REVOLUT", "XMR", 1.31],
|
||||||
|
["bb0d817d-5d7d-4e76-8d81-7d5d7d9e76fd", "EmmanuelMuema", "233.34", "REVOLUT", "XMR", 1.32],
|
||||||
|
["a53a9770-69ba-43fc-ba97-7069bad3fc1a", "EmmanuelMuema", "235.13", "REVOLUT", "XMR", 1.33],
|
||||||
|
["9c7e4b21-359c-4953-be4b-21359c095370", "EmmanuelMuema", "236.93", "REVOLUT", "XMR", 1.34],
|
||||||
|
["88c72c50-3162-4c91-872c-503162dc9176", "Alphabay", "358.80", "REVOLUT", "XMR", 2.02],
|
||||||
],
|
],
|
||||||
"GBP": [
|
"GBP": [
|
||||||
["15e821b8-e570-4b0f-a821-b8e5709b0ffc", "SecureMole", "166.08", "REVOLUT", 1.27],
|
["15e821b8-e570-4b0f-a821-b8e5709b0ffc", "SecureMole", "167.95", "REVOLUT", "XMR", 1.28],
|
||||||
["071ab272-ba37-4a14-9ab2-72ba37fa1484", "Boozymad89", "166.08", "REVOLUT", 1.27],
|
["071ab272-ba37-4a14-9ab2-72ba37fa1484", "Boozymad89", "167.95", "REVOLUT", "XMR", 1.28],
|
||||||
["850f28eb-ce63-4ca7-8f28-ebce63dca707", "topmonero", "166.34", "REVOLUT", 1.27],
|
["6727d9e5-c038-43f5-a7d9-e5c038c3f5be", "topmonero", "168.22", "REVOLUT", "XMR", 1.28],
|
||||||
["6727d9e5-c038-43f5-a7d9-e5c038c3f5be", "topmonero", "166.34", "REVOLUT", 1.27],
|
["850f28eb-ce63-4ca7-8f28-ebce63dca707", "topmonero", "168.22", "REVOLUT", "XMR", 1.28],
|
||||||
["ca4feeb9-22d5-456d-8fee-b922d5c56d27", "Boozymad89", "175.51", "REVOLUT", 1.34],
|
["ca4feeb9-22d5-456d-8fee-b922d5c56d27", "Boozymad89", "177.49", "REVOLUT", "XMR", 1.36],
|
||||||
["15e821b8-e570-4b0f-a821-b8e5709b0ffc", "SecureMole", "166.08", "REVOLUT", 1.27],
|
["78db95b7-e090-48e2-9b95-b7e09098e2d9", "Crypto_Hood", "38150.99", "REVOLUT", "BTC", 1.18],
|
||||||
["071ab272-ba37-4a14-9ab2-72ba37fa1484", "Boozymad89", "166.08", "REVOLUT", 1.27],
|
|
||||||
["850f28eb-ce63-4ca7-8f28-ebce63dca707", "topmonero", "166.34", "REVOLUT", 1.27],
|
|
||||||
["6727d9e5-c038-43f5-a7d9-e5c038c3f5be", "topmonero", "166.34", "REVOLUT", 1.27],
|
|
||||||
["ca4feeb9-22d5-456d-8fee-b922d5c56d27", "Boozymad89", "175.51", "REVOLUT", 1.34],
|
|
||||||
],
|
|
||||||
"SEK": [
|
|
||||||
["f0e840b9-29ab-4a6f-a840-b929ab7a6fde", "topmonero", "2020.45", "REVOLUT", 1.25],
|
|
||||||
["2252a3f7-6d6b-400b-92a3-f76d6bb00b50", "SwishaMonero", "2020.45", "REVOLUT", 1.25],
|
|
||||||
["f0e840b9-29ab-4a6f-a840-b929ab7a6fde", "topmonero", "2020.45", "REVOLUT", 1.25],
|
|
||||||
["2252a3f7-6d6b-400b-92a3-f76d6bb00b50", "SwishaMonero", "2020.45", "REVOLUT", 1.25],
|
|
||||||
],
|
|
||||||
"CZK": [
|
|
||||||
["80aa52ef-a5d3-462c-aa52-efa5d3862cbe", "topmonero", "4872.73", "REVOLUT", 1.3],
|
|
||||||
["80aa52ef-a5d3-462c-aa52-efa5d3862cbe", "topmonero", "4872.73", "REVOLUT", 1.3],
|
|
||||||
],
|
],
|
||||||
|
"NZD": [["0addd244-c5cb-40bf-9dd2-44c5cbd0bff4", "topmonero", "351.40", "REVOLUT", "XMR", 1.31]],
|
||||||
|
"CAD": [["388442b4-0cb7-48f3-8442-b40cb7f8f39d", "topmonero", "296.50", "REVOLUT", "XMR", 1.32]],
|
||||||
}
|
}
|
||||||
|
|
||||||
currency_map = {
|
expected_to_update = [
|
||||||
"CZK": [["80aa52ef-a5d3-462c-aa52-efa5d3862cbe", "topmonero", "4872.73", "REVOLUT", 1.3]],
|
["fb04a8e2-3c69-45f3-84a8-e23c6975f380", "coingeckoxmrusd*usdchf*1.3", "XMR", "CHF", False],
|
||||||
"GBP": [
|
["bf12756b-0138-49ca-9275-6b0138f9caf1", "coingeckoxmrusd*usdmxn*1.3", "XMR", "MXN", False],
|
||||||
["15e821b8-e570-4b0f-a821-b8e5709b0ffc", "SecureMole", "166.08", "REVOLUT", 1.27],
|
["ef1455dc-4629-4827-9455-dc46291827f0", "coingeckoxmrusd*usddkk*1.3", "XMR", "DKK", False],
|
||||||
["071ab272-ba37-4a14-9ab2-72ba37fa1484", "Boozymad89", "166.08", "REVOLUT", 1.27],
|
["388442b4-0cb7-48f3-8442-b40cb7f8f39d", "coingeckoxmrusd*usdcad*1.3", "XMR", "CAD", False],
|
||||||
["850f28eb-ce63-4ca7-8f28-ebce63dca707", "topmonero", "166.34", "REVOLUT", 1.27],
|
["b5be2881-4491-4a60-be28-814491ca606a", "coingeckoxmrusd*usdpln*1.3", "XMR", "PLN", False],
|
||||||
["6727d9e5-c038-43f5-a7d9-e5c038c3f5be", "topmonero", "166.34", "REVOLUT", 1.27],
|
["3c5068ce-fcf9-40cc-9068-cefcf920cc02", "coingeckoxmrusd*usdtry*1.3", "XMR", "TRY", False],
|
||||||
["ca4feeb9-22d5-456d-8fee-b922d5c56d27", "Boozymad89", "175.51", "REVOLUT", 1.34],
|
["b23aa3b3-4c91-42e4-baa3-b34c9162e4e0", "coingeckoxmrusd*usdhkd*1.3", "XMR", "HKD", False],
|
||||||
],
|
["f886768f-b9c9-4cf7-8676-8fb9c9ccf7ee", "coingeckoxmrusd*usdhuf*1.3", "XMR", "HUF", False],
|
||||||
"NOK": [["9c3d9fb6-c74c-4a35-bd9f-b6c74c7a3504", "topmonero", "2023.02", "REVOLUT", 1.3]],
|
["0addd244-c5cb-40bf-9dd2-44c5cbd0bff4", "coingeckoxmrusd*usdnzd*1.3", "XMR", "NZD", False],
|
||||||
"SEK": [
|
["24a9cad1-0bce-46f3-a9ca-d10bce86f34f", "coingeckoxmrusd*usdrub*1.3", "XMR", "RUB", False],
|
||||||
["f0e840b9-29ab-4a6f-a840-b929ab7a6fde", "topmonero", "2020.45", "REVOLUT", 1.25],
|
["80aa52ef-a5d3-462c-aa52-efa5d3862cbe", "coingeckoxmrusd*usdczk*1.3", "XMR", "CZK", False],
|
||||||
["2252a3f7-6d6b-400b-92a3-f76d6bb00b50", "SwishaMonero", "2020.45", "REVOLUT", 1.25],
|
["ac9eb9c8-88c7-4add-9eb9-c888c72addb2", "coingeckoxmrusd*usdsgd*1.3", "XMR", "SGD", False],
|
||||||
],
|
["68b50d95-91d2-4f21-b50d-9591d22f218d", "coingeckoxmrusd*usdaud*1.3", "XMR", "AUD", False],
|
||||||
"EUR": [
|
["b048bad8-3aaa-4727-88ba-d83aaa1727b6", "coingeckoxmrusd*usdjpy*1.3", "XMR", "JPY", False],
|
||||||
["65b452e3-a29f-4233-b452-e3a29fe23369", "topmonero", "184.28", "REVOLUT", 1.19],
|
["9c3d9fb6-c74c-4a35-bd9f-b6c74c7a3504", "coingeckoxmrusd*usdnok*1.3", "XMR", "NOK", False],
|
||||||
["65b452e3-a29f-4233-b452-e3a29fe23369", "topmonero", "184.28", "REVOLUT", 1.19],
|
["9a7bd726-6229-4fda-bbd7-2662295fda98", "coingeckoxmrusd*usdthb*1.3", "XMR", "THB", False],
|
||||||
["87af6467-be02-476e-af64-67be02676e9a", "topmonero", "184.28", "REVOLUT", 1.19],
|
]
|
||||||
["d2c6645c-6d56-4094-8664-5c6d5640941b", "topmonero", "184.28", "REVOLUT", 1.19],
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
cg_prices = {
|
cg_prices = {
|
||||||
"bitcoin": {
|
"bitcoin": {
|
||||||
|
|
|
@ -1,17 +1,20 @@
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock, patch
|
||||||
|
|
||||||
from tests.common import fake_public_ads, currency_map, cg_prices
|
from tests.common import fake_public_ads, cg_prices, expected_to_update
|
||||||
from agora import Agora
|
from agora import Agora
|
||||||
|
from markets import Markets
|
||||||
|
|
||||||
|
|
||||||
class TestAgora(TestCase):
|
class TestAgora(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
self.markets = Markets()
|
||||||
self.agora = Agora()
|
self.agora = Agora()
|
||||||
|
setattr(self.agora, "markets", self.markets)
|
||||||
|
|
||||||
def mock_wrap_public_ads(self, asset, currency, providers, rates):
|
def mock_wrap_public_ads(self, asset, currency, providers, rates):
|
||||||
try:
|
try:
|
||||||
return currency_map[currency]
|
return fake_public_ads[currency]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -21,3 +24,44 @@ class TestAgora(TestCase):
|
||||||
self.agora.wrap_public_ads = self.mock_wrap_public_ads
|
self.agora.wrap_public_ads = self.mock_wrap_public_ads
|
||||||
public_ads = self.agora.get_all_public_ads()
|
public_ads = self.agora.get_all_public_ads()
|
||||||
self.assertDictEqual(public_ads, fake_public_ads)
|
self.assertDictEqual(public_ads, fake_public_ads)
|
||||||
|
|
||||||
|
def test_get_all_public_ads_only_one(self):
|
||||||
|
self.agora.cg.get_price = MagicMock()
|
||||||
|
self.agora.cg.get_price.return_value = cg_prices
|
||||||
|
self.agora.wrap_public_ads = self.mock_wrap_public_ads
|
||||||
|
public_ads = self.agora.get_all_public_ads()
|
||||||
|
for currency, ads in public_ads.items():
|
||||||
|
ad_ids = [ad[0] for ad in ads]
|
||||||
|
len_ad_ids = len(ad_ids)
|
||||||
|
|
||||||
|
ad_ids_dedup = set(ad_ids)
|
||||||
|
|
||||||
|
len_ad_ids_dedup = len(ad_ids_dedup)
|
||||||
|
|
||||||
|
self.assertEqual(len_ad_ids, len_ad_ids_dedup)
|
||||||
|
|
||||||
|
@patch("twisted.internet.threads.deferToThread")
|
||||||
|
def test_run_cheat_in_thread(self, defer):
|
||||||
|
asset1 = self.agora.run_cheat_in_thread()
|
||||||
|
|
||||||
|
asset2 = self.agora.run_cheat_in_thread()
|
||||||
|
self.assertEqual(set([asset1, asset2]), set(["XMR", "BTC"]))
|
||||||
|
|
||||||
|
asset3 = self.agora.run_cheat_in_thread()
|
||||||
|
|
||||||
|
asset4 = self.agora.run_cheat_in_thread()
|
||||||
|
|
||||||
|
self.assertEqual(set([asset3, asset4]), set(["XMR", "BTC"]))
|
||||||
|
|
||||||
|
self.assertNotEqual(asset1, asset2)
|
||||||
|
self.assertNotEqual(asset3, asset4)
|
||||||
|
|
||||||
|
def test_update_prices(self):
|
||||||
|
self.agora.cg.get_price = MagicMock()
|
||||||
|
self.agora.cg.get_price.return_value = cg_prices
|
||||||
|
self.agora.wrap_public_ads = self.mock_wrap_public_ads
|
||||||
|
|
||||||
|
self.agora.slow_ad_update = MagicMock()
|
||||||
|
self.agora.update_prices()
|
||||||
|
call_args = self.agora.slow_ad_update.call_args_list[0][0][0]
|
||||||
|
self.assertCountEqual(call_args, expected_to_update)
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
from unittest import TestCase
|
||||||
|
from tests.common import fake_public_ads, expected_to_update
|
||||||
|
from markets import Markets
|
||||||
|
from agora import Agora
|
||||||
|
|
||||||
|
|
||||||
|
class TestMarkets(TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.markets = Markets()
|
||||||
|
self.agora = Agora()
|
||||||
|
|
||||||
|
def test_autoprice(self):
|
||||||
|
ads = [
|
||||||
|
["2b6dba4d-c9db-48f2-adba-4dc9dba8f2a0", "Xpoterlolipop", "182.80", "REVOLUT", "XMR", 1.18],
|
||||||
|
["57e3e8d6-45fe-40da-a3e8-d645fe20da46", "SecureMole", "183.26", "REVOLUT", "XMR", 1.19],
|
||||||
|
["87af6467-be02-476e-af64-67be02676e9a", "topmonero", "183.42", "REVOLUT", "XMR", 1.19],
|
||||||
|
["65b452e3-a29f-4233-b452-e3a29fe23369", "topmonero", "183.42", "REVOLUT", "XMR", 1.19],
|
||||||
|
["d2c6645c-6d56-4094-8664-5c6d5640941b", "topmonero", "183.42", "REVOLUT", "XMR", 1.19],
|
||||||
|
]
|
||||||
|
currency = "EUR"
|
||||||
|
margin = self.markets.autoprice(ads, currency)
|
||||||
|
expected_margin = 1.18
|
||||||
|
self.assertEqual(margin, expected_margin)
|
||||||
|
|
||||||
|
def test_get_new_ad_equation(self):
|
||||||
|
to_update = self.markets.get_new_ad_equations(fake_public_ads)
|
||||||
|
self.assertCountEqual(to_update, expected_to_update)
|
||||||
|
|
||||||
|
res_xmr = self.markets.get_new_ad_equations(fake_public_ads, ["XMR"])
|
||||||
|
expected_xmr_to_update = [x for x in expected_to_update if x[2] == "XMR"]
|
||||||
|
self.assertCountEqual(res_xmr, expected_xmr_to_update)
|
||||||
|
|
||||||
|
res_btc = self.markets.get_new_ad_equations(fake_public_ads, ["BTC"])
|
||||||
|
expected_btc_to_update = [x for x in expected_to_update if x[2] == "BTC"]
|
||||||
|
self.assertCountEqual(res_btc, expected_btc_to_update)
|
||||||
|
|
||||||
|
res_both = self.markets.get_new_ad_equations(fake_public_ads, ["XMR", "BTC"])
|
||||||
|
self.assertCountEqual(res_both, expected_to_update)
|
Loading…
Reference in New Issue