Ejemplo n.º 1
0
def update_price_feed() :
    global derived_prices, config
    state = {}

    for asset in _all_assets + [core_symbol]:
        price_median_blockchain[asset] = 0.0
        lastUpdate[asset]              = datetime.utcnow()
        myCurrentFeed[asset]           = {}

    if configFile.blame != "latest" :
        blameFile = config.configPath + "/blame/" + configFile.blame + ".json"
        if os.path.isfile(blameFile) :
            # Load data from disk for (faster) debugging and verification
            with open(blameFile, 'r') as fp:
                state = json.load(fp)
                # Load feed sources
                feed  = state["feed"]
                # Load configuration from old state
                configStruct = state["config"]
                for key in configStruct :
                    # Skip asset config
                    if key == "asset_config" :
                        continue
                    config.__dict__[key] = configStruct[key]

        else :
            sys.exit("Configuration error: Either set 'blame' to an existing " +
                     "block number from the blame/ to verify or set it to " +
                     "'latest' to run the script online! ")
    else :
        # Load configuration from file
        config = configFile
        # Get prices online from sources
        pool = futures.ThreadPoolExecutor(max_workers=8)
        feed      = {}
        mythreads = {}

        for name in config.feedSources :
            print("(%s)" % name, end="", flush=True)
            mythreads[name] = pool.submit(config.feedSources[name].fetch)

        for name in config.feedSources :
            print(".", end="", flush=True)
            feed[name] = mythreads[name].result()

    # rpc variables about bts rpc ##############################################
    rpc = GrapheneAPI(config.host, config.port, config.user, config.passwd)
    fetch_from_wallet(rpc)

    # Determine bts price ######################################################
    derived_prices = derive_prices(feed)

    # Only publish given feeds #################################################
    price_feeds = {}
    update_required = False

    for asset in asset_list_publish :

        # Get Final Price according to price metric
        this_asset_config = config.asset_config[asset] if asset in config.asset_config else config.asset_config["default"]
        price_metric      = this_asset_config["metric"] if "metric" in this_asset_config else config.asset_config["default"]["metric"]
        if (asset not in derived_prices or
                core_symbol not in derived_prices[asset] or
                price_metric not in derived_prices[asset][core_symbol]) :
            print("Warning: Asset %s has no derived price!" % asset)
            continue
        if float(derived_prices[asset][core_symbol][price_metric]) > 0.0:
            quote_precision_core = assets[asset]["precision"]
            symbol         = assets[asset]["symbol"]
            assert symbol is not asset
            base_precision_cer  = assets[blockchain_feed_quote[asset]]["precision"]  # core asset
            core_price_cer      = derived_prices[asset][core_symbol][price_metric] * 10 ** (quote_precision_core - base_precision_cer)
            core_price_cer      = fractions.Fraction.from_float(core_price_cer).limit_denominator(100000)
            denominator_cer     = core_price_cer.denominator
            numerator_cer       = core_price_cer.numerator

            quote_precision_settle = assets[asset]["precision"]
            symbol          = assets[asset]["symbol"]
            assert symbol is not asset
            base_precision_settle  = assets[blockchain_feed_quote[asset]]["precision"]  # core asset
            core_price_settle      = derived_prices[asset]["short_backing_asset"][price_metric] * 10 ** (quote_precision_settle - base_precision_settle)
            core_price_settle      = fractions.Fraction.from_float(core_price_settle).limit_denominator(100000)
            denominator_settle     = core_price_settle.denominator
            numerator_settle       = core_price_settle.numerator

            price_feed = {"settlement_price": {
                          "quote": {"asset_id": assets[blockchain_feed_quote[asset]]["id"],
                                    "amount": denominator_settle
                                    },
                          "base": {"asset_id": assets[asset]["id"],
                                   "amount": numerator_settle
                                   }
                          },
                          "maintenance_collateral_ratio" :
                              config.asset_config[symbol]["maintenance_collateral_ratio"]
                              if (symbol in config.asset_config and "maintenance_collateral_ratio" in config.asset_config[symbol])
                              else config.asset_config["default"]["maintenance_collateral_ratio"],
                          "maximum_short_squeeze_ratio"  :
                              config.asset_config[symbol]["maximum_short_squeeze_ratio"]
                              if (symbol in config.asset_config and "maximum_short_squeeze_ratio" in config.asset_config[symbol])
                              else config.asset_config["default"]["maximum_short_squeeze_ratio"],
                          "core_exchange_rate": {
                          "quote": {"asset_id": "1.3.0",
                                    "amount": int(denominator_cer * (
                                        config.asset_config[symbol]["core_exchange_factor"]
                                        if (symbol in config.asset_config and "core_exchange_factor" in config.asset_config[symbol])
                                        else config.asset_config["default"]["core_exchange_factor"]))
                                    },
                          "base": {"asset_id": assets[asset]["id"],
                                   "amount": numerator_cer
                                   }}}
            asset_update_required = publish_rule(rpc, asset)
            if asset_update_required :
                update_required = True
            price_feeds[symbol] = {"asset_id": assets[asset]["id"],
                                   "feed":     price_feed,
                                   "publish":  asset_update_required
                                   }
        else :
            print("Warning: Asset %s has a negative derived price of %f (%s metric)!" % (asset, float(derived_prices[asset][price_metric]), price_metric))
            continue

    if not debug :
        # Print some stats ##########################################################
        print_stats(price_feeds)

        # Verify results or store them ##############################################
        configStruct = {}
        for key in dir(config) :
            if key[0] == "_" :
                continue
            if key == "feedSources" :
                continue
            if key == "feedsources" :
                continue
            if key == "subprocess"  :
                continue
            if key == "os"          :
                continue
            configStruct[key] = config.__dict__[key]
        # Store State
        state["feed"]           = feed
        state["derived_prices"] = derived_prices
        state["price_feeds"]    = price_feeds
        state["lastblock"]      = get_last_block(rpc)
        state["config"]         = configStruct
        blameFile               = config.configPath + "/blame/" + str(state["lastblock"]) + ".json"
        with open(blameFile, 'w') as fp:
            json.dump(state, fp)
        print("Blamefile: " + blameFile)

        # Check publish rules and publich feeds #####################################
        if update_required and not debug :
            publish = False
            if config.ask_confirmation :
                if rpc._confirm("Are you SURE you would like to publish this feed?") :
                    publish = True
            else :
                publish = True

            if publish :
                print("Update required! Forcing now!")
                update_feed(rpc, price_feeds)
        else :
            print("no update required")

    else :
        # Verify results
        print()
        print("[Warning] This script is loading old data for debugging. No price can be published.\n" +
              "          Please set 'blame' to 'latest' if you are ready to go online!")
        print()
        compare_feeds(state["derived_prices"], derived_prices)
Ejemplo n.º 2
0
def update_price_feed():
    global derived_prices, config
    state = {}

    for asset in _all_assets + [core_symbol]:
        price_median_blockchain[asset] = 0.0
        lastUpdate[asset] = datetime.utcnow()
        myCurrentFeed[asset] = {}

    if configFile.blame != "latest":
        blameFile = config.configPath + "/blame/" + configFile.blame + ".json"
        if os.path.isfile(blameFile):
            # Load data from disk for (faster) debugging and verification
            with open(blameFile, 'r') as fp:
                state = json.load(fp)
                # Load feed sources
                feed = state["feed"]
                # Load configuration from old state
                configStruct = state["config"]
                for key in configStruct:
                    # Skip asset config
                    if key == "asset_config":
                        continue
                    config.__dict__[key] = configStruct[key]

        else:
            sys.exit(
                "Configuration error: Either set 'blame' to an existing " +
                "block number from the blame/ to verify or set it to " +
                "'latest' to run the script online! ")
    else:
        # Load configuration from file
        config = configFile
        # Get prices online from sources
        pool = futures.ThreadPoolExecutor(max_workers=8)
        feed = {}
        mythreads = {}

        for name in config.feedSources:
            print("(%s)" % name, end="", flush=True)
            mythreads[name] = pool.submit(config.feedSources[name].fetch)

        for name in config.feedSources:
            print(".", end="", flush=True)
            feed[name] = mythreads[name].result()

    # rpc variables about bts rpc ##############################################
    rpc = GrapheneAPI(config.host, config.port, config.user, config.passwd)
    fetch_from_wallet(rpc)

    # Determine bts price ######################################################
    derived_prices = derive_prices(feed)

    # Only publish given feeds #################################################
    price_feeds = {}
    update_required = False

    for asset in asset_list_publish:

        # Get Final Price according to price metric
        this_asset_config = config.asset_config[
            asset] if asset in config.asset_config else config.asset_config[
                "default"]
        price_metric = this_asset_config[
            "metric"] if "metric" in this_asset_config else config.asset_config[
                "default"]["metric"]
        if (asset not in derived_prices
                or core_symbol not in derived_prices[asset]
                or price_metric not in derived_prices[asset][core_symbol]):
            print("Warning: Asset %s has no derived price!" % asset)
            continue
        if float(derived_prices[asset][core_symbol][price_metric]) > 0.0:
            quote_precision_core = assets[asset]["precision"]
            symbol = assets[asset]["symbol"]
            assert symbol is not asset
            base_precision_cer = assets[blockchain_feed_quote[asset]][
                "precision"]  # core asset
            core_price_cer = derived_prices[asset][core_symbol][
                price_metric] * 10**(quote_precision_core - base_precision_cer)
            core_price_cer = fractions.Fraction.from_float(
                core_price_cer).limit_denominator(100000)
            denominator_cer = core_price_cer.denominator
            numerator_cer = core_price_cer.numerator

            quote_precision_settle = assets[asset]["precision"]
            symbol = assets[asset]["symbol"]
            assert symbol is not asset
            base_precision_settle = assets[blockchain_feed_quote[asset]][
                "precision"]  # core asset
            core_price_settle = derived_prices[asset]["short_backing_asset"][
                price_metric] * 10**(quote_precision_settle -
                                     base_precision_settle)
            core_price_settle = fractions.Fraction.from_float(
                core_price_settle).limit_denominator(100000)
            denominator_settle = core_price_settle.denominator
            numerator_settle = core_price_settle.numerator

            price_feed = {
                "settlement_price": {
                    "quote": {
                        "asset_id": assets[blockchain_feed_quote[asset]]["id"],
                        "amount": denominator_settle
                    },
                    "base": {
                        "asset_id": assets[asset]["id"],
                        "amount": numerator_settle
                    }
                },
                "maintenance_collateral_ratio":
                config.asset_config[symbol]["maintenance_collateral_ratio"] if
                (symbol in config.asset_config
                 and "maintenance_collateral_ratio"
                 in config.asset_config[symbol]) else
                config.asset_config["default"]["maintenance_collateral_ratio"],
                "maximum_short_squeeze_ratio":
                config.asset_config[symbol]["maximum_short_squeeze_ratio"] if
                (symbol in config.asset_config
                 and "maximum_short_squeeze_ratio"
                 in config.asset_config[symbol]) else
                config.asset_config["default"]["maximum_short_squeeze_ratio"],
                "core_exchange_rate": {
                    "quote": {
                        "asset_id":
                        "1.3.0",
                        "amount":
                        int(denominator_cer *
                            (config.asset_config[symbol]
                             ["core_exchange_factor"] if
                             (symbol in config.asset_config
                              and "core_exchange_factor"
                              in config.asset_config[symbol]) else config.
                             asset_config["default"]["core_exchange_factor"]))
                    },
                    "base": {
                        "asset_id": assets[asset]["id"],
                        "amount": numerator_cer
                    }
                }
            }
            asset_update_required = publish_rule(rpc, asset)
            if asset_update_required:
                update_required = True
            price_feeds[symbol] = {
                "asset_id": assets[asset]["id"],
                "feed": price_feed,
                "publish": asset_update_required
            }
        else:
            print(
                "Warning: Asset %s has a negative derived price of %f (%s metric)!"
                % (asset, float(
                    derived_prices[asset][price_metric]), price_metric))
            continue

    if not debug:
        # Print some stats ##########################################################
        print_stats(price_feeds)

        # Verify results or store them ##############################################
        configStruct = {}
        for key in dir(config):
            if key[0] == "_":
                continue
            if key == "feedSources":
                continue
            if key == "feedsources":
                continue
            if key == "subprocess":
                continue
            if key == "os":
                continue
            configStruct[key] = config.__dict__[key]
        # Store State
        state["feed"] = feed
        state["derived_prices"] = derived_prices
        state["price_feeds"] = price_feeds
        state["lastblock"] = get_last_block(rpc)
        state["config"] = configStruct
        blameFile = config.configPath + "/blame/" + str(
            state["lastblock"]) + ".json"
        with open(blameFile, 'w') as fp:
            json.dump(state, fp)
        print("Blamefile: " + blameFile)

        # Check publish rules and publich feeds #####################################
        if update_required and not debug:
            publish = False
            if config.ask_confirmation:
                if rpc._confirm(
                        "Are you SURE you would like to publish this feed?"):
                    publish = True
            else:
                publish = True

            if publish:
                print("Update required! Forcing now!")
                update_feed(rpc, price_feeds)
        else:
            print("no update required")

    else:
        # Verify results
        print()
        print(
            "[Warning] This script is loading old data for debugging. No price can be published.\n"
            +
            "          Please set 'blame' to 'latest' if you are ready to go online!"
        )
        print()
        compare_feeds(state["derived_prices"], derived_prices)