Josh-McFarlin/CryptoCompareAPI

a few extensions

Closed this issue · 4 comments

Hi Josh

This project is useful, many thanks. I've had to hack a few extensions in to get it to do what I need though. Rather than a PR I'll just leave them here for you to do with as you wish as they need to be applied to all methods and better integrated.

  1. Add some more fields
    `
    public static History getHourFullargs(String fromSym, String toSym, int limit, String exchange, int aggregate, Integer toTs)
    throws IOException, OutOfCallsException {
    String formattedUrl = String.format("https://min-api.cryptocompare.com/data/histohour?fsym=%s&tsym=%s&limit=%d&e=%s&aggregate=%d",
    fromSym.toUpperCase(), toSym.toUpperCase(), limit, exchange, aggregate);

     if (toTs != null) {
     	formattedUrl = String.format("%s&toTs=%d", formattedUrl, toTs);
     }
     
     System.out.println(formattedUrl);
     
     Reader r = Connection.getJSON(new URL(formattedUrl), CallTypes.HISTO);
     return new Gson().fromJson(r, History.class);
    

    }
    `

  2. Wrap for limits > 2000:
    `
    private static List getHourHistory(CurrencyPair pair, int hours) throws IOException, OutOfCallsException {
    int samples = hours;
    List listData = new LinkedList<>();
    Integer timeFrom = null;
    Set listTimes = new HashSet<>(hours);

     boolean done = false;
     
     while (!done) {
     	// only returns ~2000 at a time
     	Historic.History history = Historic.getHourFullargs(pair.base.toString(), pair.counter.toString(), samples, "Cryptopia", 1, timeFrom);
    

// System.out.println(history.timeFrom + ", " + history.data.size());

		timeFrom = history.timeFrom - 1 ;	// start time of samples
		samples -= history.data.size();

// listData.addAll(history.data);

		for (Data data : history.data) {
			if (listTimes.contains(data.time)) {
				System.out.println("Duplicate timestamp: " + data.time + ", record ignored.");
			} else {
				listTimes.add(data.time);
				listData.add(data);
			}
		}
		
		if ((samples <= 0)
			||(history.timeFrom <= 0)
			||(history.data.size() <= 0)
			){
			done = true;
		}
	}

// System.out.println(listData.size());
return listData;
}
`

  1. Useful for debugging:
    @Override public String toString() { return "Data [time=" + time + " (" +Instant.ofEpochSecond(time) + ")" + ", open=" + open + ", high=" + high + ", low=" + low + ", close=" + close + ", volumeFrom=" + volumeFrom + ", volumeTo=" + volumeTo + "]"; }

Yes I've been working on adding the optional fields and limits, and the debugging is a good idea. I'll have this updated in the next few weeks.

Here's a couple more things:

It might be best for the routine to return data guaranteed to be time-sequenced. I've modified my code above to use a TreeMap and also modified the rejection of duplicate timestamps to use that instead.

Also there's the possibility of loss of precision converting stringed numbers to doubles. Might it not be better to use BigDecimals or something similar?

Cryptocompare is now sending null data tuplets for dates when it has no values. I've added this code:

`// CryptoCompare is now sending empty values instead of saying it has no data, eg:
// Data [time=1434664800 (2015-06-18T22:00:00Z), open=0.0, high=0.0, low=0.0, close=0.0, volumeFrom=0.0, volumeTo=0.0]
// Iterate through the time-sorted list deleting everything until we find the first real data.

	Iterator<Integer> iter = mapData.keySet().iterator();
	
	while (iter.hasNext()) {
		Integer k = iter.next();
		
		Data v = mapData.get(k);
		
		if (v.open == 0.0d
				&& v.high == 0.0d
				&& v.low == 0.0d
				&& v.close == 0.0d
				&& v.volumeFrom == 0.0d
				&& v.volumeTo == 0.0d) {
			iter.remove();
		} else {
			break; // stop when we reach first real value
		}

	}`

After working on different projects for some time, I came back and implemented these features.