Requesting exchange rates for crypto pairs in code the easy way

in #programming7 years ago (edited)

Here is some simple code to get the current rates for crypto currency pairs using the CryptoCompare API.

It is written in C# but should be simple enough to translate to other languages.

Might be a fun challenge to translate to other languages. If you do this post in the comments or write a piece and link back to my post :)

Anyway on with the post. The CryptoCompare API is simple enough, here is the request.

https://min-api.cryptocompare.com/data/price?fsym=XXX&tsyms=YYY

So ETH to USD would be

https://min-api.cryptocompare.com/data/price?fsym=ETH&tsyms=USD

The response is a simple JSON stream. A valid response being:

{"USD":315.98}

And an error being

{
    "Response":"Error",
    "Message":"Additional supply depots required. (Invalid Market)",
    "Data":[],
    "Type":99
}

So to request the rate for a pair I have this simple class:

public static class PriceRequester
{
    private const string ErrorResponseKey = "Message";

    public static async Task<Either<decimal, string>> 
        GetExchangeRate(string from, string to)
    {
        try
        {
            using (var client = new HttpClient())
            {
                var response = await client
                    .GetStringAsync(
                        $"https://min-api.cryptocompare.com/data/price?fsym={from}&tsyms={to}")
                    .ConfigureAwait(false);

                return ResponseParser(from, to, response);
            }
        }
        catch (Exception ex)
        {
            return $"Failed to get rate for {from} in {to}: {ex.Message}".ToLeft<decimal, string>();
        }
    }

    public static Either<decimal, string> 
        ResponseParser(string from, string to, string walletResponse)
    {
        var parser = JsonObject.Parse(walletResponse);

        if (parser.Keys.Contains(ErrorResponseKey))
        {
            return parser[ErrorResponseKey].GetString().ToLeft<decimal, string>();
        }

        return ((decimal)parser[to].GetNumber()).ToRight<decimal, string>();
    }
}

So it performs an async request to the API, if it gets a response that is parsed and returned as a rate or an error using an Either Monad.

You call it as follows.

var ethValue = PriceRequester.GetExchangeRate("ETH", "USD").Result;

The Either Monad is stolen from Haskell, a bit out of scope for this article but I have included the code to be complete.

It is either a Right value, this is a success value, or a Left value which is what is left if not valid. That is Haskell people for you :)

public static class Either
{
    public static Either<TRight, TLeft> ToRight<TRight, TLeft>(this TRight right)
        => new Either<TRight, TLeft>.RightInstance(right);

    public static Either<TRight, TLeft> ToLeft<TRight, TLeft>(this TLeft left)
        => new Either<TRight, TLeft>.LeftInstance(left);
}

public abstract class Either<TRight, TLeft>
{
    public abstract TRight Right { get; }

    public abstract TLeft Left { get; }

    public abstract bool IsRight { get; }

    public abstract bool IsLeft { get; }

    public abstract Either<TRightResult, TLeft> 
        Select<TRightResult>(Func<TRight, TRightResult> map);

    public abstract Either<TRightResult, TLeft> 
        SelectMany<TRightResult>(Func<TRight, Either<TRightResult, TLeft>> map);

    internal class RightInstance : Either<TRight, TLeft>
    {
        public RightInstance(TRight right)
        {
            Right = right;
        }

        public override TRight Right { get; }

        public override TLeft Left
            => throw new InvalidOperationException("Either is not Right");

        public override bool IsRight => true;

        public override bool IsLeft => false;

        public override Either<TRightResult, TLeft> 
            Select<TRightResult>(Func<TRight, TRightResult> map)
            => map(Right).ToRight<TRightResult, TLeft>();

        public override Either<TRightResult, TLeft> 
            SelectMany<TRightResult>(Func<TRight, Either<TRightResult, TLeft>> map)
            => map(Right);
    }

    internal class LeftInstance : Either<TRight, TLeft>
    {
        public LeftInstance(TLeft left)
        {
            Left = left;
        }

        public override TRight Right
            => throw new InvalidOperationException("Either is not Right");

        public override TLeft Left { get; }

        public override bool IsRight => false;

        public override bool IsLeft => true;

        public override Either<TRightResult, TLeft>
            Select<TRightResult>(Func<TRight, TRightResult> map)
            => Left.ToLeft<TRightResult, TLeft>();

        public override Either<TRightResult, TLeft> 
            SelectMany<TRightResult>(Func<TRight, Either<TRightResult, TLeft>> map)
            => Left.ToLeft<TRightResult, TLeft>();
    }
}

Hope you found this helpful. Leave comments or questions below.

Happy coding

Woz

Sort:  

When I played around with a bot, I used the tools for Python linked on the bittrex homepage. There's also a script on github to load the historic price charts.

Coin Marketplace

STEEM 0.19
TRX 0.15
JST 0.029
BTC 63657.90
ETH 2656.15
USDT 1.00
SBD 2.84