1

`` I am trying to order a vector of coins to be traded in order of their market cap rank. it compiles perfectly and runs but throws an error 3 at runtime. code found below.

debugging: json.hpp Throws unhandled exception Unhandled exception at 0x0000500000000000 in MyProgram.exe: Microsoft C++ exception: nlohmann::json_abi_v3_11_2::detail::type_error at memory location 0x000000E000000000.

JSON_THROW(type_error::create(302, concat("type must be number, but is ", j.type_name()), &j));

Desired Outcome: orders my vector of coins from highest market cap to lowest after requesting market cap rank from api. and lists vector to terminal.

trading.h

#ifndef TRADING_H
#define TRADING_H

#include <string>
#include <iostream>
#include <vector>

using namespace std;

class trading{
    private:
        vector<string> coins;

    public:
        trading();
        void order();
        void listOrder();

};

trading.cpp

#include <string>
#include <iostream>
#include <vector>
#include <cpr/cpr.h>
#include <nlohmann/json.hpp>
#include "trading.h"

// for convenience
using json = nlohmann::json;

using namespace cpr;
using namespace std;


//orders the coins from 1-20 ascending order
void trading::order(){
    //variables
    vector<string> coinsCopy;
    int rankOrder = 0;

    //order coing by market cap
    string base = "https://api.coingecko.com/api/v3/search?query=";
    string id;

    //makes a copy of coins
    for (int k = 0; k < coins.size(); k++) {
        coinsCopy.push_back(coins[k]);
    }


    for (int i = 0; i < coins.size(); i++) {
        //loop variables
        string id = coins[i];
        auto search = Get(Url{ base + id });
        json data = json::parse(search.text);

        //collects rank 
        for (json& item : data["coins"]) {
            rankOrder = item["market_cap_rank"];
            if (rankOrder > coins.size()) {
                rankOrder = coins.size();
            }
            break;
        }

        //updates coins to correct order in coins copy
        coinsCopy.at(rankOrder) = coins[i];
    }

    //updates main coin vector with correct rank order
    for (int ii = 0; ii < coins.size(); ii++) {
        coins.at(rankOrder) = coinsCopy[ii];
    }
}

void trading::listOrder() {
    for (int j = 0; j < coins.size(); j++) {
        cout << "Coin Ranked # " << j << ": " << coins[j] << endl;
    }
}

Main.cpp

#include <cpr/cpr.h>
#include <iostream>
#include <nlohmann/json.hpp>
#include <string>
#include <vector>
#include "trading.h"

// for convenience
using json = nlohmann::json;

using namespace cpr;
using namespace std;


int main() {
    
    trading trade;

    
    trade.order();
    trade.listOrder();
    
}

sample of JSON FILE

{"coins":[{"id":"bitcoin","name":"Bitcoin","api_symbol":"bitcoin","symbol":"BTC","market_cap_rank":1,"thumb":"https://assets.coingecko.com/coins/images/1/thumb/bitcoin.png","large":"https://assets.coingecko.com/coins/images/1/large/bitcoin.png"},

Coins Vector

Coin Ranked # 0: bitcoin
Coin Ranked # 1: ethereum
Coin Ranked # 2: tether
Coin Ranked # 3: binancecoin
Coin Ranked # 4: usd-coin
Coin Ranked # 5: binance-usd
Coin Ranked # 6: ripple
Coin Ranked # 7: dogecoin
Coin Ranked # 8: cardano
Coin Ranked # 9: matic-network
Coin Ranked # 10: polkadot
Coin Ranked # 11: staked-ether
Coin Ranked # 12: shiba-inu
Coin Ranked # 13: okb
Coin Ranked # 14: litecoin
Coin Ranked # 15: dai
Coin Ranked # 16: tron
Coin Ranked # 17: solana
Coin Ranked # 18: uniswap
Coin Ranked # 19: avalanche-2
John Doe
  • 47
  • 6
  • 1
    Please reduce your code to a [mre]. As the message is telling you, you are trying to parse something as a number which isn't a number. It shouldn't be hard to figure out which part of the JSON is causing that by removing parts. Also a lot in your program is not relevant to the parsing issue and hinders reproducibility (e.g. replace the queries with a test JSON in a literal). – user17732522 Dec 06 '22 at 04:49
  • Well, did you try stepping through the code with a debugger to see why the exception has been thrown? – Quimby Dec 06 '22 at 05:37
  • json data = json::parse(search.text); //This is where the exception is being thrown. the why is listed in the actual question above. – John Doe Dec 06 '22 at 18:40

1 Answers1

0

There are numerous tokens having null "market_cap_rank", e.g. "xi-token" at the moment. The library fails to convert null rank to an integer value. The problem is caused by the lack of data validation.

Also note that the code

vector<string> coinsCopy;
//...
for (int k = 0; k < coins.size(); k++) {
    coinsCopy.push_back(coins[k]);
}
//...
if (rankOrder > coins.size()) {
    rankOrder = coins.size();
}    
//...
coinsCopy.at(rankOrder) = coins[i];

throws depending on the actual rankOrder value.

Edits

I feel the need to make my answer more elaborate by adding missing details.

By means of the following Python3 script, we obtain the top 20 coins sorted in the ascending order by "market_cap_rank".

import requests
import json
import operator

def receive_coins():
    resp = requests.get(r'https://api.coingecko.com/api/v3/search')
    with open("response", 'w', encoding = 'utf-8') as response:
        response.write(resp.text)
        
def get_top20():    
    with open('response', 'r', encoding = 'utf-8') as response:
        jresp = json.load(response)
        coinlist = [
            (coin['id'], coin['market_cap_rank']) for coin in jresp['coins'] if coin['market_cap_rank']
        ]        
        return sorted(coinlist, key=operator.itemgetter(1))[:20]
    return []

print(get_top20())

They are

[('bitcoin', 1), ('ethereum', 2), ('tether', 3), ('binancecoin', 4), ('usd-coin', 5), ('binance-usd', 6), ('ripple', 7), ('dogecoin', 8), ('cardano', 9), ('matic-network', 10), ('polkadot', 11), ('staked-ether', 12), ('litecoin', 13), ('shiba-inu', 14), ('okb', 15), ('dai', 16), ('solana', 17), ('tron', 18), ('uniswap', 19), ('avalanche-2', 20)]

The "market_cap_rank" values span from 1 to 20, not from 0 to 19. From the question statement, we infer that there are precisely 20 elements in the coinsCopy array, which proves my second point that the line coinsCopy.at(rankOrder) = coins[i]; throws an exception.

Another issue stems from the lack of data validation. The line auto search = Get(Url{ base + id }); repeats 20 times with negligible intervals. This may cause a site protection triggered, which results with receiving a site-specific unexpected response. The response contents are not validated in any case.

panik
  • 231
  • 1
  • 4
  • well the request should only get the market cap rank of the coins i specified which are all in the top 20 ranked coins currently. and also i checked each one in main and seem to display the correct market cap rank. Also i only grab the first market rank from the json data then break. – John Doe Dec 06 '22 at 18:47
  • @CraigForbes please post here the contents of the `coins`. It looks like the only missing part. – panik Dec 06 '22 at 19:20
  • @CraigForbes you can also provide the contents of the "trading.h" file by editing the question. – panik Dec 06 '22 at 19:24
  • @CraigForbes I requested `query=ripple` and received all the listed `coins` having `market_cap_rank = null`. – panik Dec 07 '22 at 10:05