ctubio / tribeca

Self-hosted crypto trading bot (automated high frequency market making) in node.js, angular, typescript and c++
https://127.0.0.1:3000
Other
95 stars 26 forks source link

STDEV: Feedback / Improvement / (mini) Bug #83

Closed Camille92 closed 7 years ago

Camille92 commented 7 years ago

Hello Carles, @Beegmon and everyone, I'm opening a new issue for more clarity

After trying and playing around with Stdev here are my conclusions! First of all, thank you for spending time and make it possible Carles, it's a great plus to the bot and I'm very happy that it helps you making profits 😄

Feedback and possible improvements: After playing with it I can say:

I don't believe the default settings are optimum and I changed them on my computer and did different tries during the afternoon.

The problem is that it takes too long to adjust so Tribeca and accumulate over time. This can lead to a pretty bad situation where the market is going in one direction but you can't follow as your width is ever increasing. It happened to me while testing, the market dropped by 10 or 15 dollars in a few minutes and I couldn't sell my bitcoin because the stdev was getting too high!

I overcame this problem by: 1) Changing the value of a "tick" from one minute to 1 second: It gives the opportunity to take into account spikes that might last just a few seconds to calculate the volatility. It allows reducing the time span (or 'lag') of the indicator with still enough data points to make it relevant.

2) Reducing the time: I've been trying different settings (10mn, 5mn, 3mn and currently 1mn) and I'm very happy with those results. I haven't found the "best" time span yet but I believe it is somewhere between 1mn and 5mn with a tick of 1 second/

3) Changing the formula: From: unrounded.askPx = Math.max(fv.price + this._stdev.latest / 2, unrounded.askPx); to: unrounded.askPx = Math.max(fv.price + this._stdev.latest, unrounded.askPx);

This idea here is that your input value is already the FV so what you get from STDEV is how much the price varies from FV, up or down. No need to divide it by two ;).

Possible improvements: Another way to overcome the issue I've encountered is to give the possibility to deactivate STDEV when APR is on. So that you'll still be able to get on a train or sell in case it is needed.

Little bug: I've encounter one little bug: STDEV doesn't work on alt market (where the minTick is very low -> 0.00001) and not that well on LTC/USD (min tick 0.001) After reviewing the code I think it comes from here: https://github.com/ctubio/tribeca/blob/master/src/server/statistics.ts#L132

'1e-3' should be replaced by MinTick so that it works in all markets even when the price of the good is very low and doesn't move that much in the decimals.

To sum up:

I'm amazed by how well it works for a first implementation! Usually, you need a lot of tweaking and trying before getting similar results. It's a very good job!

Even tough if you agree with me here are some tweaking that can help: 1) Replacing '1e-3' by minTick 2) Removing the / 2 in the formula 3) Changing in https://github.com/ctubio/tribeca/blob/master/src/server/statistics.ts#L105 "minutes" by "seconds" 4) Allowing users to chose the seconds in the webUI so that they can experiment themselves and develop different strategies. 5) Allowing to deactivate it if APR is on :)

Tell me what you think about all that and good trading to everyone!

Camille92 commented 7 years ago

I just thought about that this morning: If we want to be a bit more precise, we can improve the results by replacing the inputs from FV to best bid and best ask.

This way STDEV will reflect the width better (and we have 2X more data point which is always better to be precise).

A bit of the concept behind: When we take FV it's already a mean of Best Bid and Best Ask and we compare the evolution of the price. But let's imagine that the width increases a lot while FV stays relatively the same, then STDEV will not be aware of it and will go down.

In the contrary, if we take Best.Bid & Best.Ask as inputs in the same case STDEV will increase consequently and protects us from trading with a small width ;).

PS: I really hope I don't sound too "picky" and like a "never-happy-asshole". Don't get me wrong Stdev is great and I realize it represents a lot of work from your side! I'm just thinking that we can never be too good so when I know how to (mathematically) improve something I like to share it with you.

Peace! 👍

ctubio commented 7 years ago

ok about your first msg, all OK! just one question; Even if now the X seconds are customizable, the amount of periods of "20" is still always 20 so it can be hardcoded? soo.. we will read 20 times the FV value in periods of X seconds defined by user? and calculate the stdev takin into account only the last 20? or the amount of "20" should be variable too (like the seconds will be)?

ctubio commented 7 years ago

about your second msg, just one question :P: currently STDEV is calculated based on a serie of 20 values of a single unit (fv), but if now we have 2 units (best bid & best ask) to be serialized in 2 different groups of 20 to calculate the stdev.. how we do it? xD we calculate the stdev of each group of each unit and do something (wish we only need to sum it xDD) with the result of both? (excuse my ignorance!" xD) ooor.. maybe now we have 2 stdev values? one for bid side and another for ask side? oor...?

Camille92 commented 7 years ago

Hey Carles,

What I think would be the best way to do it is to put 1 second as hard coded (meaning the value is updated every 1 second) and make the 20 changeable.

For my tests in my computer, I changed https://github.com/ctubio/tribeca/blob/master/src/server/statistics.ts#L120 I changed the ''this.fvs = this.fvs.slice(-20);'' by -60 or -120 etc. depending on what I wanted to try. :)

For instance, if you want to keep 20mn, you change it to 1200 so Tribeca will look at the past 1200 seconds. :)

For the practical solution of calculating STDEV with the best bid and best ask I was thinking of creating a new variable that would keep all the values of best bid and best ask (so instead of having 20 values we would have 40) and would need to get rid of the two oldest one each time it is actualized instead of only one.

But actually, after reading your comment I think that your solution (having a Stdev bid and a Stdev Ask) sounds very promising and would probably work very well as well, possiby even better than the one I proposed! So I would say let's go for this one! 🥇 (Or the easiest to code for you!)

Then we just need to do: unrounded.askPx = Math.max(fv.price + this._stdevASK.latest, unrounded.askPx); unrounded.bidPx = Math.max(fv.price - this._stdevBID.latest, unrounded.askPx);

And it's good! :D

ctubio commented 7 years ago

hope it is better now'¡ please note, even if the stdev is internally calculated every second, in the UI is only displayed in the chart every minute maximum (may need to improve this another day)

Camille92 commented 7 years ago

Hello Carles thanks for the update,

I don't see the Stdev on the chart with Bitcoin-denominated markets (LTC/BTC etc).

Can I assume it's working?

beegmon commented 7 years ago

I finally got a chance to pull this fix down and give it a run and it is working great. I love that I can now tune STDEV!

I do have one question that was asked previously. Is running EWMA and STDEV together ok, or should one just run EWMA, or STDEV separately? I am going to run some tests of my own but wanted to see if there was any opinion on this.

Camille92 commented 7 years ago

I'm not a fan of EWMA (imho it is only useful in markets with low liquidity) but it should be able to work together.

STDEV tries to find a correct 'width' according to the volatility of the market, the more volatile the bigger the width. EWMA just checks that you sell above and buy under the EWMA 100 minutes. :)

beegmon commented 7 years ago

Yeah I agree with you as well. EWMA never really worked well for markets that moved a lot within the 100 minutes. It missed a lot of opportunities, which is why I never really ran with it.

I was just checking my assumption that both could be run if you wanted. I am running only STDEV at this point, and will likely forgo using EWMA unless I am in a market that slow and it makes sense.

Thanks!

Camille92 commented 7 years ago

yes!

After some reflection, I think the option of calculating with both best bid and best ask might be an option to try. I'll see if I can make that happen and share it with you :)

ctubio commented 7 years ago

Hello Camille,

charts do not display values if are equal to 0, so i presume in your case the stdev result may be 0.

also charts display the same value over time over and over until forever meanwhile the value is not updated (values are currently inherit from 1 frame of time to the next).

i would like to fix this 2 lil issues in the chartsin during the following days. But appart of this, i can't imagine why you didnt saw stdev in the chart; pleae let me know if you think that your issue may be caused by another thing, thanks'¡

Camille92 commented 7 years ago

Ok no problem well I guess for bitcoin-denominated markets value must be around 0.00001.

If it's calculated but not shown there is no problem :)

Camille92 commented 7 years ago

Hey guys, after doing some testing, I can confirm you that it's very interesting to use Stdev with both best Bid and best Ask as inputs.

The problem is that now Stdev is like a T-Rex, a very powerful animal but that can see only moving objects. Similarly, Stdev (both FV and on sides) can only work well when the price is moving and doesn't take into consideration the current width.

For instance, look at this screenshot FYI Stdev FAIR has been modified and represents BestBid and BestAsk. capture d ecran 2017-05-18 a 11 21 31

At that moment the price did not move that much so Stdev big and Ask are very low, but Stdev Best Bid&Ask is already at 1.59 because it takes into account the current/past width.

It will protect you from trading with a too narrow separation if an order comes in the middle!

And when the price moves a bit you get pretty similar results! capture d ecran 2017-05-18 a 11 28 12

In the end, it's just having best of both worlds!

On a technical side I did it by changing: this._lastFV.push(filteredMkt.bids[0].price,filteredMkt.asks[0].price); this._lastFV = this._lastFV.slice(-this._qlParamRepo.latest.widthStdevPeriods*2)

You have to multiply by 2 because you now have twice the data in this lastFv !

Ps: Can you tell me if it keeps accumulating or it is cleaned from time to time? (Because adding value every second, after two days you already have 172 800 data point!

ctubio commented 7 years ago

in charts data points are added non-stop (but once every 7 seconds), and then are removed when they are older than 6hours

in internal sequences, slice function does the job to keep them limited to x periods.

ctubio commented 7 years ago

ok so, if we apply the new magic codes of:

this._lastFV.push(filteredMkt.bids[0].price,filteredMkt.asks[0].price);
this._lastFV = this._lastFV.slice(-this._qlParamRepo.latest.widthStdevPeriods*2)

the question isss... should still be called OnFV? xD

i vote for rename OnFV to OnSides (and add to the MANUAL that this works by applying in both sides the same stdev sequence, based on best bid/ask) i vote for rename OnSides to OnSide (and add to MANUAL that this works by applying independently 2 sequence of stdev, one in each side, based on best bid/ask)

Camille92 commented 7 years ago

Well, I was thinking about keeping the two old ones (I don't know if someone will use them, but why not offer the opportunity).

And this one "OnTops", so the names are a bit more distinct ;)

But it's your call !

ctubio commented 7 years ago

yea i preffer too to keep them all 3 :P thanks for your inputs'¡

Camille92 commented 7 years ago

The last tip which I can think is useful is to add a "multiplier" option to Stdev in order to choose for a more aggressive or more "relaxed" strategy and still be protected.

That can be done by allowing to input a number here: `unrounded.bidPx = Math.min(fv.price - this._stdev.latest * NUMBER https://github.com/ctubio/tribeca/blob/master/src/server/quoting-engine.ts#L178

For instance, for a little bit more aggressive strategy you can replace number by 0.9, for a very aggressive one replace it by 0.5. In the contrary for trading less but only having great opportunities, you can choose 1.1 or 1.2.

If you put 0.9 this means that you'll put orders at a minimum of 90% the standard deviation of the price. This can be good if you often want to be on top of the market without falling into the trap of stupidly low width ;) .

And then I think Stev is perfect!

ctubio commented 7 years ago

allright all fixed'¡

e67977a005f638980128ef069f47ca07_gif-02-manos-ala-obra-gif_450-360

many thanks Camille''' hope you don't miss nothing (appart from the multiplier that i will do tomorrow)

ctubio commented 7 years ago

hope you agree, "multiplier" was too long xD