tarkah / tickrs

Realtime ticker data in your terminal 📈
MIT License
1.16k stars 58 forks source link

Stock prices beyond two decimal places #123

Closed jasongaare closed 1 year ago

jasongaare commented 3 years ago

Great tool, I instantly loved it.

I have OTC penny stocks, which often are represented to 4 decimal places.

tickrs rounds all the prices to two places, (it seems) so the data and charts a little less-than-compelling.

Screen Shot 2021-04-29 at 3 28 47 PM

Would it be possible to support more decimal places, perhaps as a config options (even per symbol would be awesome!)

tarkah commented 3 years ago

Great suggestion! I never even realized this. I could always just hard code it... so anything under ~$2 goes to the 4th decimal place?

Do you have any suggestions on what a good cutoff would be before stock prices start moving in 0.01+ increments?

miraclx commented 3 years ago

How about we vary it based on the abs max-min delta within the active timeframe? In order to chart out reasonable fluctuations. So it doesn't require hardcoding, works for wholes and decimals alike, and can better spread out charts like the one above.

jasongaare commented 3 years ago

I like the idea of using the delta. I'm not sure what the threshold is for when the decimals get truncated more.

tarkah commented 3 years ago

Yeah I think that's the way to go. I'm out of town for a few days, but I'll toy with this when I get back.

It should be super easy to implement, so if anyone wants to help contribute, that'd be great as well!

tarkah commented 3 years ago

Ok, I've implemented this in #125. Here is an example:

image

I take the difference between the min and max price within the timeframe, and if it's <= 1.0, then I show 4 decimal places. Seems to work well!

tarkah commented 3 years ago

@miraclx @jasongaare Can you both test for me for a few days and give me your thoughts on if things should be refined? I think I went too aggressive with the $1.0 delta cutoff, as that'd trigger on a $100 stock with < 1% movement from high to low.

I should have waited to release, but oh well :P

tarkah commented 3 years ago

Maybe an alternative implementation would look at the period over period price change for the entire time frame, and take the median price change from that. If median is less than $0.01, it's a good candidate for 4 decimals?

miraclx commented 3 years ago

I should have waited to release, but oh well :P

😅, I was literally in the process of reviewing and eventually testing the PR when it got merged, I thought, "oh, you're in a hurry".

tarkah commented 3 years ago

So I tried the method of calculating period over period price movements, then taking the median, and seeing if it was <= $0.005 (half a cent) and this seems to work really well. However, it massively increases CPU usage due to the calculation...

Any other thoughts?

miraclx commented 3 years ago

Hmm. Could you open a draft PR for this? Lemme inspect that for a sec.

tarkah commented 3 years ago

Yeah, check out #126. My other concern is that any calc on "price movement" will more likely have false positives when there is not a lot of data (early in the trading period), as there are less data points.

I'm thinking the easiest way is to just hard code 4 decimals on stocks with a High price of ~<$2.

tarkah commented 3 years ago

And to clarify, this now JUST impacts the "formatting" of decimal places.

I've fixed the issue where it doesn't graph from top to bottom, which was a separate issue. (I was adding 0.05 padding to high and low price for y-axis bounds, which caused stocks with low prices to be affected), which I removed.

miraclx commented 3 years ago

Thought about this for a sec...I still think I approve of the already merged PR. A stock with < 1% movement in any timeframe should be in four decimal places irrespective of whether or not it's a penny stock or WDYT? This makes sense to me, to graph out reasonable fluctuations like you set out to do in the first place.

Maybe I'm ignorant, but I'm not sure the method of taking median is much of a solution. The gained cost from the required heap allocation, eventual sorting, only to end up, like you said, producing false positives (which I believe would happen more often than not), I don't really think is helpful.

I'll look at it again in the morning, perhaps I'm missing something.

Also, on heap allocation, StockState::high_low could be rewritten without the Vec ```diff diff --git a/src/widget/stock.rs b/src/widget/stock.rs index 60be048..433d384 100644 --- a/src/widget/stock.rs +++ b/src/widget/stock.rs @@ -413,29 +413,27 @@ impl StockState { (min, max) } - pub fn high_low(&self, data: &[Price]) -> (f64, f64) { - let mut data = data.to_vec(); - data.push(Price { - close: self.current_price(), - open: self.current_price(), - high: self.current_price(), - low: self.current_price(), - ..Default::default() - }); - data.retain(|p| p.close.gt(&0.0)); - - let high = data + pub fn high_low(&self, prices: &[Price]) -> (f64, f64) { + let data = prices .iter() - .max_by(|a, b| a.high.partial_cmp(&b.high).unwrap()) - .map(|p| p.high) - .unwrap_or(1.0); - let low = data - .iter() - .min_by(|a, b| a.low.partial_cmp(&b.low).unwrap()) - .map(|p| p.low) - .unwrap_or(0.0); + .cloned() + .chain(std::iter::once(Price { + close: self.current_price(), + open: self.current_price(), + high: self.current_price(), + low: self.current_price(), + ..Default::default() + })) + .filter(|p| p.close.gt(&0.0)); + + let (high, low) = data.fold((None::, None::), |(pre_h, pre_l), price| { + ( + Some(pre_h.map_or(price.high, |pre_h| pre_h.max(price.high))), + Some(pre_l.map_or(price.low, |pre_l| pre_l.min(price.low))), + ) + }); - (high, low) + (high.unwrap_or(1.0), low.unwrap_or(0.0)) } pub fn x_bounds(&self, start: i64, end: i64, data: &[Price]) -> [f64; 2] { ```
jasongaare commented 3 years ago

Not sure the status on this, I still have version 0.14.5... here's a screenshot:

Screen Shot 2021-05-12 at 2 27 02 PM

if you went with the previous solution, is it simply possible to round numbers? Here you can see HYSR and KODK both are getting data with four decimal points, but PBR is always showing x.xx00. Would it be simple to just round of trailing zeros in this case? (not beyond two decimals, obviously)

tarkah commented 3 years ago

Unfortunately >2 decimal precision prices aren't just something that happens on low prices stocks. SPY, for example, is trading around ~400 and it goes out to like 8 decimal places.

@miraclx I really don't think it's worth showing more than 2 decimal precision on anything above a certain price, even if its movement is small for the day. At $5, a $0.01 change is only 0.2%. I think I will go with the original implementation, but add a second check that ONLY shows 4 decimal places if the High price is also lower than $5.

tidux commented 2 years ago

High precision is desirable for crypto pairs since BTC price tends to dwarf anything else. Check tickrs -s ETH-BTC to reproduce.

Screenshot 2022-01-24 051245

tarkah commented 2 years ago

@tidux I've implemented a better way to dynamically add precision based on the asset price. See #134.

Let me know if you think this works.

image

tidux commented 2 years ago

That looks good.