blackbird icon indicating copy to clipboard operation
blackbird copied to clipboard

Currency strings and Multi-currency support

Open CCKRK opened this issue 7 years ago • 7 comments

Hi all,

I know that this issue has been brought up before ( you can see discussions in #234 and #221 ) but I'm hoping we can get a fresh take on the issue. Basically, as I'm trying to implement simultaneous trades across multiple exchanges I've started to notice the little quirks of how we are passing Leg1 and Leg2 currency symbols to each exchange and really believe it needs to be dealt with in a more organized manner. I've given it a lot of thought and, I believe, really the only way of normalizing the pair we are intending to trade is to do a mapping on each exchange. An abstract exchange class is nice, but all of the solutions I've seen do not even work for the first case. BTC-USD on Kraken, for example, is XXBTZUSD and no bidirectional calls will solve this. A solution that I thought of, at least as the first iteration with "minimal" changes, would be to add two members to each exchange like:

std::string symbolTransform(Parameters& Params); std::string marketPairTransform(Parameters& params);

Kraken would do something like:

  if (currency.compare("BTC")==0){
    return "XXBT";
  
  } else if (currency.compare("USD")==0){
    return "ZUSD";

  } else if (currency.compare("ETH")==0){
    return "XETH";

  } else { 
    std::cout << "<Kraken> WARNING: Currency not supported." << std::endl;
    return "";
  }
}

These members would output leg1 and leg2 in the form the individual exchange expects them to be expressed (BTC=XXBT, marketPair = XXBTZUSD, etc.) and could be called in the exchange members where appropriate. I'm concerned about performance, tons of "If.compare() else" is not great, and I have no idea how much this would slow down execution of the curl requests -- also this obviously requires a lot of maintenance if/when exchanges change their symbols but that is already sort of present.

Supporting more currencies is really more of a by-product of a change like this. Simply adding new if/then conditions to the symbolTransform of a given exchange to support the desired currency would be possible. If Parallelism ends up being added it would be possible to save symbol/marketUrl so less calls of these functions are necessary.

I'd love to see a better way/some different ideas on how to handle this. Also if anyone reads those old issues and knows a bit about Reactivex I'd love to talk to you -- It's probably outside of the scope of BlackBird but it really seems in line with what is really trying to be accomplished with parallelism and I want to give it a try locally.

CCKRK avatar Feb 16 '18 18:02 CCKRK

I would like to see multiple currency pairs working. GDAX does not allow me to use USD because the country I am from, but EUR would be working. I probably could replace hardcoded currency strings in source, but from this issue it does not seem trivial.

I'm not a C++ developer, but if exchanges use different codes for currencies in API, I would say your proposed solution is generally correct design.

I wouldn't be afraid of a few string comparisons, I don't think this would make any problem. Only improvement could be use switch instead of if then else if... :)

About ReactiveX - depends - would RxJava experience help? ;)

davidjirovec avatar Feb 18 '18 21:02 davidjirovec

Replacing the hardcoded strings has weird effects without the change, I would not recommend it.

As for RxJava the thing is the java/js libraries are (seemingly) so simple, they basically come out of the box thread safe with nice neat little functions to create subscribers. What I was attempting to do was to remap BlackBirds quotes into streams like

exch1 ---- a ---- b ---- a--b--> exch2 -a--b--b----a--b--a-->

further remap to a flat_map_latest:

spread ---ab-ab--ab--ab--ab->

have that spreadstream be calculated in check_entry_exit on_update

check_entry_exit --x---x----x---x--x ->

and the end of the pipeline is our actionable buy/sell signal. Eventually, a workflow like that would allow for preprocessing of bid/ask for volume adjustments + slippage, essentially eliminate the issue of getting stuck on a single leg and the slowdown of a poor REST API (eg bittrex), make a much easier websocket integration, and open up HFT/MM for anyone interested. I just think it's a little out of my depth at the moment... it took me all night to pass a pointer through a subscriber and block the thread. Still don't know how to pool/ASIO.

CCKRK avatar Feb 18 '18 23:02 CCKRK

Ok I am not sure what is the exact question for me here :) But if you would already have observable for each exchange, CombineLatest seems to be good operator to use.

davidjirovec avatar Feb 19 '18 13:02 davidjirovec

Hah yeah sorry, I guess the question is whether that is an appropriate pattern. Observables for each exchange is the hard part I suppose --

CCKRK avatar Feb 19 '18 16:02 CCKRK

Hard part maybe, but I would say correct.

Observable per exchange, based on websockets. For exchanges not supporting websockets, also create observable, but this observable would be based on loop calling exchange via rest api. All of this happening in parallel.

Then combine results of these observables using CombineLatest to observable of current price ratios. Then decide if buy/sell.

That is a lot of async code. I am not sure how hard it is to implement in C++, but it should bring lower latency than asking synchronously in a loop with few seconds interval, which I would say should help to catch more opportunities.

Another idea came into my mind - to further reduce latency remove price checking in two steps. Do not ask for ticker and then for order book to calculate the real price. Always download just order book and calculate price based on order book and our amount needed to buy/sell.

I've read nice article here https://bitcoin.stackexchange.com/questions/49819/cryptocurrency-arbitrage-what-do-i-need-to-know

Look at Caveats and risks - I would say 1, 2 - this is why websockets are good and overall network latencies should be minimized 2, 4, 5 - not big issue with Blackbird 3, 6 - well... :)

davidjirovec avatar Feb 19 '18 17:02 davidjirovec

The amount of async seems daunting right now, but I suppose I'm here to improve my skills as well as the bots.

So I agree that in an ideal situation BlackBird could drop the first step of price checking, maybe keep it in demo mode or something like that. We would need to change the way order book factor works, and all around it would be much more complex, especially in a parallel trading situation. Additionally, the way all of our exchanges order book checking works is not very optimized ( and that's ok, optimization comes later ) so that would need to be changed.

3 and 6 are really the main reasons we can make any money at all. Markets have matured over time, I can't run my simple javascript bot and make a killing anymore, but the engineering problems with working with multiple exchanges (some of them terrible) presents a barrier to entry so our opportunities are still alive.

CCKRK avatar Feb 19 '18 17:02 CCKRK

While it's not a market-neutral shorting solution like Blackbird (and it's Javascript, not C++), I tackled the multi-currency problem as configurable strings in the database. It's worked out well and has been easy to add new currencies / trading pairs: https://github.com/Riedeman/cryptopro.

And there's plenty of opportunities still out there.

Riedeman avatar Jun 06 '18 10:06 Riedeman