diff --git a/tests/test_currencyrate.py b/tests/test_currencyrate.py index 94a44f103ff6..e60403aa52f9 100644 --- a/tests/test_currencyrate.py +++ b/tests/test_currencyrate.py @@ -5,7 +5,7 @@ from utils import wait_for, only_one from pyln.client import RpcError from fixtures import * # noqa: F401,F403 -from flask import Flask, jsonify +from flask import Flask, jsonify, request from werkzeug.serving import make_server @@ -45,9 +45,16 @@ def median_rate(rateslist): return range(int(rate * 0.99), int(rate * 1.01)) -def test_apis_batch1(node_factory): +def test_apis_mocked_batch1(node_factory, fake_rateserver): opts = { - "currencyrate-disable-source": ["bitstamp", "coinbase"], + "currencyrate-disable-source": ALL_RESOURCES, + "currencyrate-add-source": [ + f"my-coingecko,{fake_rateserver['url']}/api/v3/simple/price?ids=bitcoin&vs_currencies={{currency_lc}},bitcoin,{{currency_lc}}", + f"my-kraken,{fake_rateserver['url']}/0/public/Ticker?pair=XXBTZ{{currency}},result,XXBTZ{{currency}},c,0", + f"my-blockchain.info,{fake_rateserver['url']}/ticker,{{currency}},last", + f"my-coindesk,{fake_rateserver['url']}/index/cc/v1/latest/tick?market=cadli&instruments=BTC-{{currency}}&apply_mapping=true,Data,BTC-{{currency}},VALUE", + f"my-binance,{fake_rateserver['url']}/api/v3/ticker/price?symbol=BTC{{currency}},price", + ], } l1 = node_factory.get_node(options=opts) @@ -55,28 +62,28 @@ def test_apis_batch1(node_factory): LOGGER.info(rateslist) rates = {entry["source"]: entry["amount"] for entry in rateslist} - assert "bitstamp" not in rates - assert "coinbase" not in rates + for ressource in ALL_RESOURCES: + assert ressource not in rates - assert "coingecko" in rates - assert "kraken" in rates - assert "blockchain.info" in rates - assert "coindesk" in rates - assert "binance" in rates + assert "my-coingecko" in rates + assert "my-kraken" in rates + assert "my-blockchain.info" in rates + assert "my-coindesk" in rates + assert "my-binance" in rates # Death to the 58k gang! - assert rates["coingecko"] > 58000 - assert rates["kraken"] > 58000 - assert rates["blockchain.info"] > 58000 - assert rates["coindesk"] > 58000 - assert rates["binance"] > 58000 + assert rates["my-coingecko"] > 58000 + assert rates["my-kraken"] > 58000 + assert rates["my-blockchain.info"] > 58000 + assert rates["my-coindesk"] > 58000 + assert rates["my-binance"] > 58000 rates = [ - rates["coingecko"], - rates["kraken"], - rates["blockchain.info"], - rates["coindesk"], - rates["binance"], + rates["my-coingecko"], + rates["my-kraken"], + rates["my-blockchain.info"], + rates["my-coindesk"], + rates["my-binance"], ] rates.sort() @@ -91,56 +98,12 @@ def test_apis_batch1(node_factory): assert int(l1.rpc.currencyrate("usd")['rate']) in median_rate(rateslist) -def test_apis_batch2(node_factory): - opts = { - "currencyrate-disable-source": [ - "coingecko", - "kraken", - "blockchain.info", - "coindesk", - "binance", - ], - } - l1 = node_factory.get_node(options=opts) - - rateslist = l1.rpc.call("listcurrencyrates", ["USD"])['currencyrates'] - LOGGER.info(rateslist) - rates = {entry["source"]: entry["amount"] for entry in rateslist} - - assert "bitstamp" in rates - assert "coinbase" in rates - - assert "coingecko" not in rates - assert "kraken" not in rates - assert "blockchain.info" not in rates - assert "coindesk" not in rates - assert "binance" not in rates - - assert rates["bitstamp"] > 0 - assert rates["coinbase"] > 0 - - rates = [ - rates["bitstamp"], - rates["coinbase"], - ] - rates.sort() - - convert = l1.rpc.call("currencyconvert", [100, "USD"]) - LOGGER.info(convert) - - assert "msat" in convert - assert convert["msat"] > 0 - assert convert["msat"] in median_conversion(100, rateslist) - - assert int(l1.rpc.currencyrate("USD")['rate']) in median_rate(rateslist) - - -def test_custom_source(node_factory): +def test_apis_mocked_batch2(node_factory, fake_rateserver): opts = { "currencyrate-disable-source": ALL_RESOURCES, "currencyrate-add-source": [ - r"my-coingecko,https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies={currency_lc},bitcoin,{currency_lc}", - r"my-kraken,https://api.kraken.com/0/public/Ticker?pair=XXBTZ{currency},result,XXBTZ{currency},c,0", + f"my-bitstamp,{fake_rateserver['url']}/api/v2/ticker/btc{{currency_lc}},last", + f"my-coinbase,{fake_rateserver['url']}/v2/prices/BTC-{{currency}}/spot,data,amount", ], } l1 = node_factory.get_node(options=opts) @@ -149,23 +112,21 @@ def test_custom_source(node_factory): LOGGER.info(rateslist) rates = {entry["source"]: entry["amount"] for entry in rateslist} - assert "bitstamp" not in rates - assert "coinbase" not in rates + assert "my-bitstamp" in rates + assert "my-coinbase" in rates + assert "coingecko" not in rates assert "kraken" not in rates assert "blockchain.info" not in rates assert "coindesk" not in rates assert "binance" not in rates - assert "my-coingecko" in rates - assert "my-kraken" in rates - - assert rates["my-coingecko"] > 0 - assert rates["my-kraken"] > 0 + assert rates["my-bitstamp"] > 0 + assert rates["my-coinbase"] > 0 rates = [ - rates["my-coingecko"], - rates["my-kraken"], + rates["my-bitstamp"], + rates["my-coinbase"], ] rates.sort() @@ -193,8 +154,19 @@ def test_no_sources(node_factory): LOGGER.info(rates) -def test_invalid_currency(node_factory): - opts = {} +def test_invalid_currency(node_factory, fake_rateserver): + opts = { + "currencyrate-disable-source": ALL_RESOURCES, + "currencyrate-add-source": [ + f"my-coingecko,{fake_rateserver['url']}/api/v3/simple/price?ids=bitcoin&vs_currencies={{currency_lc}},bitcoin,{{currency_lc}}", + f"my-kraken,{fake_rateserver['url']}/0/public/Ticker?pair=XXBTZ{{currency}},result,XXBTZ{{currency}},c,0", + f"my-blockchain.info,{fake_rateserver['url']}/ticker,{{currency}},last", + f"my-coindesk,{fake_rateserver['url']}/index/cc/v1/latest/tick?market=cadli&instruments=BTC-{{currency}}&apply_mapping=true,Data,BTC-{{currency}},VALUE", + f"my-binance,{fake_rateserver['url']}/api/v3/ticker/price?symbol=BTC{{currency}},price", + f"my-bitstamp,{fake_rateserver['url']}/api/v2/ticker/btc{{currency_lc}},last", + f"my-coinbase,{fake_rateserver['url']}/v2/prices/BTC-{{currency}}/spot,data,amount", + ], + } l1 = node_factory.get_node(options=opts) with pytest.raises( @@ -204,13 +176,13 @@ def test_invalid_currency(node_factory): rates = l1.rpc.call("listcurrencyrates", ["XXX"]) LOGGER.info(rates) - l1.daemon.wait_for_logs(["failed to get `XXX` rate from bitstamp", - "failed to get `XXX` rate from coinbase", - "failed to get `XXX` rate from coingecko", - "failed to get `XXX` rate from kraken", - "failed to get `XXX` rate from blockchain.info", - "failed to get `XXX` rate from coindesk", - "failed to get `XXX` rate from binance"]) + l1.daemon.wait_for_logs(["failed to get `XXX` rate from my-bitstamp", + "failed to get `XXX` rate from my-coinbase", + "failed to get `XXX` rate from my-coingecko", + "failed to get `XXX` rate from my-kraken", + "failed to get `XXX` rate from my-blockchain.info", + "failed to get `XXX` rate from my-coindesk", + "failed to get `XXX` rate from my-binance"]) class _ServerThread(threading.Thread): @@ -236,6 +208,13 @@ def fake_rateserver(): "too_high": 50_000.0116, "too_low": 50_000.0114, "midpoint": 50_000.0115, + "bitstamp": 72748.45, + "coinbase": 72760.125, + "coingecko": 72732, + "kraken": 72745.00000, + "blockchain.info": 72749.07, + "coindesk": 72751.6828660636, + "binance": 72715.35000000, } @app.get("/fast") @@ -259,6 +238,494 @@ def too_low(): def midpoint(): return jsonify({"price": state["midpoint"]}) + @app.get("/api/v2/ticker/btcusd") + def bitstamp(): + return jsonify( + { + "timestamp": "1780301548", + "open": "73568.00", + "high": "74094.65", + "low": "72611.68", + "last": state["bitstamp"], + "volume": "619.76380694", + "vwap": "73542.01", + "bid": "72748.45", + "ask": "72748.46", + "side": "1", + "open_24": "73769.45", + "percent_change_24": "-1.38", + "market_type": "SPOT", + } + ) + + @app.get("/v2/prices/BTC-USD/spot") + def coinbase(): + return jsonify( + {"data": {"amount": state["coinbase"], "base": "BTC", "currency": "USD"}} + ) + + @app.get("/api/v3/simple/price") + def coingecko(): + ids = request.args.get("ids") + assert ids == "bitcoin" + vs_currencies = request.args.get("vs_currencies") + assert vs_currencies == "usd" + return jsonify({"bitcoin": {"usd": state["coingecko"]}}) + + @app.get("/0/public/Ticker") + def kraken(): + pair = request.args.get("pair") + assert pair == "XXBTZUSD" + return jsonify( + { + "error": [], + "result": { + "XXBTZUSD": { + "a": ["72745.00000", "1", "1.000"], + "b": ["72744.90000", "3", "3.000"], + "c": [state["kraken"], "0.00033610"], + "v": ["299.69911717", "640.87872182"], + "p": ["73231.75442", "73435.07382"], + "t": [17317, 39634], + "l": ["72613.70000", "72613.70000"], + "h": ["73960.00000", "74070.00000"], + "o": "73569.90000", + } + }, + } + ) + + @app.get("/ticker") + def blockchain_info(): + return jsonify( + { + "ARS": { + "15m": 1.0250388182e8, + "last": 1.0250388182e8, + "buy": 1.0250388182e8, + "sell": 1.0250388182e8, + "symbol": "ARS", + }, + "AUD": { + "15m": 101319.81, + "last": 101319.81, + "buy": 101319.81, + "sell": 101319.81, + "symbol": "AUD", + }, + "BRL": { + "15m": 366724.43, + "last": 366724.43, + "buy": 366724.43, + "sell": 366724.43, + "symbol": "BRL", + }, + "CAD": { + "15m": 100512.08, + "last": 100512.08, + "buy": 100512.08, + "sell": 100512.08, + "symbol": "CAD", + }, + "CHF": { + "15m": 56966.31, + "last": 56966.31, + "buy": 56966.31, + "sell": 56966.31, + "symbol": "CHF", + }, + "CLP": { + "15m": 6.474521862e7, + "last": 6.474521862e7, + "buy": 6.474521862e7, + "sell": 6.474521862e7, + "symbol": "CLP", + }, + "CNY": { + "15m": 492212.94, + "last": 492212.94, + "buy": 492212.94, + "sell": 492212.94, + "symbol": "CNY", + }, + "CZK": { + "15m": 1515907.76, + "last": 1515907.76, + "buy": 1515907.76, + "sell": 1515907.76, + "symbol": "CZK", + }, + "DKK": { + "15m": 466396.92, + "last": 466396.92, + "buy": 466396.92, + "sell": 466396.92, + "symbol": "DKK", + }, + "EUR": { + "15m": 62406.99, + "last": 62406.99, + "buy": 62406.99, + "sell": 62406.99, + "symbol": "EUR", + }, + "GBP": { + "15m": 54042.23, + "last": 54042.23, + "buy": 54042.23, + "sell": 54042.23, + "symbol": "GBP", + }, + "GHS": { + "15m": 890908.85, + "last": 890908.85, + "buy": 890908.85, + "sell": 890908.85, + "symbol": "GHS", + }, + "HKD": { + "15m": 570161.03, + "last": 570161.03, + "buy": 570161.03, + "sell": 570161.03, + "symbol": "HKD", + }, + "HRK": { + "15m": 335567.09, + "last": 335567.09, + "buy": 335567.09, + "sell": 335567.09, + "symbol": "HRK", + }, + "HUF": { + "15m": 2.20867545e7, + "last": 2.20867545e7, + "buy": 2.20867545e7, + "sell": 2.20867545e7, + "symbol": "HUF", + }, + "INR": { + "15m": 6908819.27, + "last": 6908819.27, + "buy": 6908819.27, + "sell": 6908819.27, + "symbol": "INR", + }, + "ISK": { + "15m": 8948137.51, + "last": 8948137.51, + "buy": 8948137.51, + "sell": 8948137.51, + "symbol": "ISK", + }, + "JPY": { + "15m": 1.160046994e7, + "last": 1.160046994e7, + "buy": 1.160046994e7, + "sell": 1.160046994e7, + "symbol": "JPY", + }, + "KRW": { + "15m": 1.0963634629e8, + "last": 1.0963634629e8, + "buy": 1.0963634629e8, + "sell": 1.0963634629e8, + "symbol": "KRW", + }, + "NGN": { + "15m": 9.982397332e7, + "last": 9.982397332e7, + "buy": 9.982397332e7, + "sell": 9.982397332e7, + "symbol": "NGN", + }, + "NZD": { + "15m": 121902.27, + "last": 121902.27, + "buy": 121902.27, + "sell": 121902.27, + "symbol": "NZD", + }, + "PLN": { + "15m": 264210.59, + "last": 264210.59, + "buy": 264210.59, + "sell": 264210.59, + "symbol": "PLN", + }, + "RON": { + "15m": 327770.94, + "last": 327770.94, + "buy": 327770.94, + "sell": 327770.94, + "symbol": "RON", + }, + "RUB": { + "15m": 5207079.39, + "last": 5207079.39, + "buy": 5207079.39, + "sell": 5207079.39, + "symbol": "RUB", + }, + "SEK": { + "15m": 672516.06, + "last": 672516.06, + "buy": 672516.06, + "sell": 672516.06, + "symbol": "SEK", + }, + "SGD": { + "15m": 92929.66, + "last": 92929.66, + "buy": 92929.66, + "sell": 92929.66, + "symbol": "SGD", + }, + "THB": { + "15m": 2371619.73, + "last": 2371619.73, + "buy": 2371619.73, + "sell": 2371619.73, + "symbol": "THB", + }, + "TRY": { + "15m": 3339917.15, + "last": 3339917.15, + "buy": 3339917.15, + "sell": 3339917.15, + "symbol": "TRY", + }, + "TWD": { + "15m": 2279715.75, + "last": 2279715.75, + "buy": 2279715.75, + "sell": 2279715.75, + "symbol": "TWD", + }, + "USD": { + "15m": 72749.07, + "last": state["blockchain.info"], + "buy": 72749.07, + "sell": 72749.07, + "symbol": "USD", + }, + } + ) + + @app.get( + "/index/cc/v1/latest/tick" + ) + def coindesk(): + market = request.args.get("market") + assert market == "cadli" + instruments = request.args.get("instruments") + assert instruments == "BTC-USD" + apply_mapping = request.args.get("apply_mapping") + assert apply_mapping == "true" + return jsonify( + { + "Data": { + "BTC-USD": { + "TYPE": "266", + "MARKET": "cadli", + "INSTRUMENT": "BTC-USD", + "CCSEQ": 1323841393, + "VALUE": state["coindesk"], + "VALUE_FLAG": "UP", + "VALUE_LAST_UPDATE_TS": 1780301570, + "VALUE_LAST_UPDATE_TS_NS": 94000000, + "LAST_UPDATE_QUANTITY": 0.105, + "LAST_UPDATE_QUOTE_QUANTITY": 7642.36250656015, + "LAST_UPDATE_VOLUME_TOP_TIER": 0, + "LAST_UPDATE_QUOTE_VOLUME_TOP_TIER": 0, + "LAST_UPDATE_VOLUME_DIRECT": 0, + "LAST_UPDATE_QUOTE_VOLUME_DIRECT": 0, + "LAST_UPDATE_VOLUME_TOP_TIER_DIRECT": 0, + "LAST_UPDATE_QUOTE_VOLUME_TOP_TIER_DIRECT": 0, + "LAST_UPDATE_CCSEQ": 1323894738, + "CURRENT_HOUR_VOLUME": 1574.29740546284, + "CURRENT_HOUR_QUOTE_VOLUME": 114448749.088967, + "CURRENT_HOUR_VOLUME_TOP_TIER": 815.533688797, + "CURRENT_HOUR_QUOTE_VOLUME_TOP_TIER": 59271744.4993065, + "CURRENT_HOUR_VOLUME_DIRECT": 129.07158333, + "CURRENT_HOUR_QUOTE_VOLUME_DIRECT": 9391081.77416094, + "CURRENT_HOUR_VOLUME_TOP_TIER_DIRECT": 112.97878943, + "CURRENT_HOUR_QUOTE_VOLUME_TOP_TIER_DIRECT": 8218412.43095265, + "CURRENT_HOUR_OPEN": 72717.6735718823, + "CURRENT_HOUR_HIGH": 72753.9349636733, + "CURRENT_HOUR_LOW": 72687.3200637837, + "CURRENT_HOUR_TOTAL_INDEX_UPDATES": 21316, + "CURRENT_HOUR_CHANGE": 34.0092941813, + "CURRENT_HOUR_CHANGE_PERCENTAGE": 0.0467689524578662, + "CURRENT_DAY_VOLUME": 60357.3494069443, + "CURRENT_DAY_QUOTE_VOLUME": 4426435661.72566, + "CURRENT_DAY_VOLUME_TOP_TIER": 30443.0356107571, + "CURRENT_DAY_QUOTE_VOLUME_TOP_TIER": 2232970539.73364, + "CURRENT_DAY_VOLUME_DIRECT": 5903.56883278, + "CURRENT_DAY_QUOTE_VOLUME_DIRECT": 433444084.0685, + "CURRENT_DAY_VOLUME_TOP_TIER_DIRECT": 5222.26007038, + "CURRENT_DAY_QUOTE_VOLUME_TOP_TIER_DIRECT": 383433774.031475, + "CURRENT_DAY_OPEN": 73595.7587259674, + "CURRENT_DAY_HIGH": 73989.4922688168, + "CURRENT_DAY_LOW": 72626.8875119395, + "CURRENT_DAY_TOTAL_INDEX_UPDATES": 751436, + "CURRENT_DAY_CHANGE": -844.0758599038, + "CURRENT_DAY_CHANGE_PERCENTAGE": -1.14690829270027, + "CURRENT_WEEK_VOLUME": 60357.3494069443, + "CURRENT_WEEK_QUOTE_VOLUME": 4426435661.72566, + "CURRENT_WEEK_VOLUME_TOP_TIER": 30443.0356107571, + "CURRENT_WEEK_QUOTE_VOLUME_TOP_TIER": 2232970539.73364, + "CURRENT_WEEK_VOLUME_DIRECT": 5903.56883278, + "CURRENT_WEEK_QUOTE_VOLUME_DIRECT": 433444084.0685, + "CURRENT_WEEK_VOLUME_TOP_TIER_DIRECT": 5222.26007038, + "CURRENT_WEEK_QUOTE_VOLUME_TOP_TIER_DIRECT": 383433774.031475, + "CURRENT_WEEK_OPEN": 73595.7587259674, + "CURRENT_WEEK_HIGH": 73989.4922688168, + "CURRENT_WEEK_LOW": 72626.8875119395, + "CURRENT_WEEK_TOTAL_INDEX_UPDATES": 751436, + "CURRENT_WEEK_CHANGE": -844.0758599038, + "CURRENT_WEEK_CHANGE_PERCENTAGE": -1.14690829270027, + "CURRENT_MONTH_VOLUME": 60357.3494069443, + "CURRENT_MONTH_QUOTE_VOLUME": 4426435661.72566, + "CURRENT_MONTH_VOLUME_TOP_TIER": 30443.0356107571, + "CURRENT_MONTH_QUOTE_VOLUME_TOP_TIER": 2232970539.73364, + "CURRENT_MONTH_VOLUME_DIRECT": 5903.56883278, + "CURRENT_MONTH_QUOTE_VOLUME_DIRECT": 433444084.0685, + "CURRENT_MONTH_VOLUME_TOP_TIER_DIRECT": 5222.26007038, + "CURRENT_MONTH_QUOTE_VOLUME_TOP_TIER_DIRECT": 383433774.031475, + "CURRENT_MONTH_OPEN": 73595.7587259674, + "CURRENT_MONTH_HIGH": 73989.4922688168, + "CURRENT_MONTH_LOW": 72626.8875119395, + "CURRENT_MONTH_TOTAL_INDEX_UPDATES": 751436, + "CURRENT_MONTH_CHANGE": -844.0758599038, + "CURRENT_MONTH_CHANGE_PERCENTAGE": -1.14690829270027, + "CURRENT_YEAR_VOLUME": 40382133.8494108, + "CURRENT_YEAR_QUOTE_VOLUME": 3024720572862.21, + "CURRENT_YEAR_VOLUME_TOP_TIER": 18474713.3425985, + "CURRENT_YEAR_QUOTE_VOLUME_TOP_TIER": 1391919922327.24, + "CURRENT_YEAR_VOLUME_DIRECT": 4744622.25510961, + "CURRENT_YEAR_QUOTE_VOLUME_DIRECT": 357398888349.34, + "CURRENT_YEAR_VOLUME_TOP_TIER_DIRECT": 4239110.93945524, + "CURRENT_YEAR_QUOTE_VOLUME_TOP_TIER_DIRECT": 318945519497.326, + "CURRENT_YEAR_OPEN": 87535.6902474645, + "CURRENT_YEAR_HIGH": 97861.0000403346, + "CURRENT_YEAR_LOW": 60230.1378018301, + "CURRENT_YEAR_TOTAL_INDEX_UPDATES": 317755603, + "CURRENT_YEAR_CHANGE": -14784.0073814009, + "CURRENT_YEAR_CHANGE_PERCENTAGE": -16.8891195575271, + "MOVING_24_HOUR_VOLUME": 127405.003580434, + "MOVING_24_HOUR_QUOTE_VOLUME": 9365693546.36435, + "MOVING_24_HOUR_VOLUME_TOP_TIER": 60402.3558377577, + "MOVING_24_HOUR_QUOTE_VOLUME_TOP_TIER": 4439843552.5359, + "MOVING_24_HOUR_VOLUME_DIRECT": 13267.19506938, + "MOVING_24_HOUR_QUOTE_VOLUME_DIRECT": 975888087.236335, + "MOVING_24_HOUR_VOLUME_TOP_TIER_DIRECT": 11797.31708835, + "MOVING_24_HOUR_QUOTE_VOLUME_TOP_TIER_DIRECT": 867716024.677109, + "MOVING_24_HOUR_OPEN": 73850.0780201078, + "MOVING_24_HOUR_HIGH": 74091.1379549413, + "MOVING_24_HOUR_LOW": 72626.8875119395, + "MOVING_24_HOUR_TOTAL_INDEX_UPDATES": 1769778, + "MOVING_24_HOUR_CHANGE": -1098.3951540442, + "MOVING_24_HOUR_CHANGE_PERCENTAGE": -1.48733106787664, + "MOVING_7_DAY_VOLUME": 1199133.54284601, + "MOVING_7_DAY_QUOTE_VOLUME": 89170297360.6635, + "MOVING_7_DAY_VOLUME_TOP_TIER": 567755.663369739, + "MOVING_7_DAY_QUOTE_VOLUME_TOP_TIER": 42224392659.4598, + "MOVING_7_DAY_VOLUME_DIRECT": 133514.54629889, + "MOVING_7_DAY_QUOTE_VOLUME_DIRECT": 9931638720.27663, + "MOVING_7_DAY_VOLUME_TOP_TIER_DIRECT": 119656.55826412, + "MOVING_7_DAY_QUOTE_VOLUME_TOP_TIER_DIRECT": 8900055491.23557, + "MOVING_7_DAY_OPEN": 77287.4872232217, + "MOVING_7_DAY_HIGH": 77996.1623459993, + "MOVING_7_DAY_LOW": 72425.5243349043, + "MOVING_7_DAY_TOTAL_INDEX_UPDATES": 12822192, + "MOVING_7_DAY_CHANGE": -4535.8043571581, + "MOVING_7_DAY_CHANGE_PERCENTAGE": -5.86874346691825, + "MOVING_30_DAY_VOLUME": 5351045.15051276, + "MOVING_30_DAY_QUOTE_VOLUME": 417521294879.772, + "MOVING_30_DAY_VOLUME_TOP_TIER": 2426602.85974405, + "MOVING_30_DAY_QUOTE_VOLUME_TOP_TIER": 189200981255.036, + "MOVING_30_DAY_VOLUME_DIRECT": 592166.62235892, + "MOVING_30_DAY_QUOTE_VOLUME_DIRECT": 46247912579.3709, + "MOVING_30_DAY_VOLUME_TOP_TIER_DIRECT": 528823.84811508, + "MOVING_30_DAY_QUOTE_VOLUME_TOP_TIER_DIRECT": 41297867333.3798, + "MOVING_30_DAY_OPEN": 78674.3049851104, + "MOVING_30_DAY_HIGH": 82813.9122924122, + "MOVING_30_DAY_LOW": 72425.5243349043, + "MOVING_30_DAY_TOTAL_INDEX_UPDATES": 58815920, + "MOVING_30_DAY_CHANGE": -5922.6221190468, + "MOVING_30_DAY_CHANGE_PERCENTAGE": -7.52802598023293, + "MOVING_90_DAY_VOLUME": 21443810.6006946, + "MOVING_90_DAY_QUOTE_VOLUME": 1570356938558.91, + "MOVING_90_DAY_VOLUME_TOP_TIER": 9043187.59509763, + "MOVING_90_DAY_QUOTE_VOLUME_TOP_TIER": 664731255517.974, + "MOVING_90_DAY_VOLUME_DIRECT": 2278659.42727248, + "MOVING_90_DAY_QUOTE_VOLUME_DIRECT": 167381245302.021, + "MOVING_90_DAY_VOLUME_TOP_TIER_DIRECT": 2038212.94183807, + "MOVING_90_DAY_QUOTE_VOLUME_TOP_TIER_DIRECT": 149739991864.236, + "MOVING_90_DAY_OPEN": 68322.3578278976, + "MOVING_90_DAY_HIGH": 82813.9122924122, + "MOVING_90_DAY_LOW": 64995.6161037856, + "MOVING_90_DAY_TOTAL_INDEX_UPDATES": 185791988, + "MOVING_90_DAY_CHANGE": 4429.325038166, + "MOVING_90_DAY_CHANGE_PERCENTAGE": 6.48298035808917, + "MOVING_180_DAY_VOLUME": 46145511.2020624, + "MOVING_180_DAY_QUOTE_VOLUME": 3538314259699.15, + "MOVING_180_DAY_VOLUME_TOP_TIER": 21450988.6383314, + "MOVING_180_DAY_QUOTE_VOLUME_TOP_TIER": 1657086029561.32, + "MOVING_180_DAY_VOLUME_DIRECT": 5473708.86307133, + "MOVING_180_DAY_QUOTE_VOLUME_DIRECT": 422383617410.788, + "MOVING_180_DAY_VOLUME_TOP_TIER_DIRECT": 4866883.41774741, + "MOVING_180_DAY_QUOTE_VOLUME_TOP_TIER_DIRECT": 374892899081.622, + "MOVING_180_DAY_OPEN": 93473.0138827925, + "MOVING_180_DAY_HIGH": 97861.0000403346, + "MOVING_180_DAY_LOW": 60230.1378018301, + "MOVING_180_DAY_TOTAL_INDEX_UPDATES": 369449298, + "MOVING_180_DAY_CHANGE": -20721.3310167289, + "MOVING_180_DAY_CHANGE_PERCENTAGE": -22.1682495898889, + "MOVING_365_DAY_VOLUME": 86535517.3539453, + "MOVING_365_DAY_QUOTE_VOLUME": 7919105726987.51, + "MOVING_365_DAY_VOLUME_TOP_TIER": 42976317.1903734, + "MOVING_365_DAY_QUOTE_VOLUME_TOP_TIER": 3992954144533.56, + "MOVING_365_DAY_VOLUME_DIRECT": 10755950.5533326, + "MOVING_365_DAY_QUOTE_VOLUME_DIRECT": 992706308387.657, + "MOVING_365_DAY_VOLUME_TOP_TIER_DIRECT": 9139552.8781168, + "MOVING_365_DAY_QUOTE_VOLUME_TOP_TIER_DIRECT": 835977511511.379, + "MOVING_365_DAY_OPEN": 105674.332934938, + "MOVING_365_DAY_HIGH": 126223.317922832, + "MOVING_365_DAY_LOW": 60230.1378018301, + "MOVING_365_DAY_TOTAL_INDEX_UPDATES": 616756418, + "MOVING_365_DAY_CHANGE": -32922.6500688744, + "MOVING_365_DAY_CHANGE_PERCENTAGE": -31.154821757090602, + "LIFETIME_FIRST_UPDATE_TS": 1279408140, + "LIFETIME_VOLUME": 1472739305.34319, + "LIFETIME_QUOTE_VOLUME": 41960116421925.8, + "LIFETIME_VOLUME_TOP_TIER": 716228852.484145, + "LIFETIME_QUOTE_VOLUME_TOP_TIER": 20989865539437.8, + "LIFETIME_VOLUME_DIRECT": 327820461.469944, + "LIFETIME_QUOTE_VOLUME_DIRECT": 6301540998901.38, + "LIFETIME_VOLUME_TOP_TIER_DIRECT": 269988661.712477, + "LIFETIME_QUOTE_VOLUME_TOP_TIER_DIRECT": 4851586542024.82, + "LIFETIME_OPEN": 0.04951, + "LIFETIME_HIGH": 126223.317922832, + "LIFETIME_HIGH_TS": 1759777112, + "LIFETIME_LOW": 0.01, + "LIFETIME_LOW_TS": 1286572500, + "LIFETIME_TOTAL_INDEX_UPDATES": 1329464334, + "LIFETIME_CHANGE": 72751.6333560636, + "LIFETIME_CHANGE_PERCENTAGE": 146943311.16151, + } + }, + "Err": {}, + } + ) + + @app.get("/api/v3/ticker/price") + def binance(): + symbol = request.args.get("symbol") + assert symbol == "BTCUSD" + return jsonify({"symbol": "BTCUSD", "price": state["binance"]}) + srv = _ServerThread(app) srv.start() try: