amv-dev / yata

Yet Another Technical Analysis library [for Rust]
Apache License 2.0
321 stars 49 forks source link

Allow peeking at last method update #19

Closed msdrigg closed 2 years ago

msdrigg commented 2 years ago

I have been working with yata's EMA struct and I am missing some functionality that makes it a bit frustrating to work with.

Right now, the only way to get at the current value of the average is to call item.next(new_value), but I want to check back later to see if this value has changed and I won't necessarily have new data when I want to check on the value. Obviously, I could write a simple wrapper like this, but I think this functionality could be useful to others.

PeekableWrapper { 
    ema: EMA,
    last: Option<f64>
}

I haven't looked at all the Method implementations in this library, so it may not be efficient or possible to peek at for all of them due to implementation challenges. To work around this, I suggest adding a new trait Peekable that lets you peek at the last updated value and implement this trait where it is possible. This wouldn't break backwards compatibility and it would allow future implementations of Peekable if it becomes possible later.

Maybe even add a .into_peekable(self) -> PeekableWrapper<Self> method on Method that takes an un-peekable item and wraps it into a peekable struct by storing the current value.

What are your thoughts on this? If you are open I would be happy to write something up in a PR.

amv-dev commented 2 years ago

Looks like interesting idea. Probably we don't need an additional trait as long as we can use Index. I need to think about this idea.

msdrigg commented 2 years ago

Are you thinking of indexing by usize or some other struct? I can't get my head around how that would work, because it is really only feasible to get the last calculated value from a method in most cases, unless you are storing many previous calculations in a buffer.

I might not have explained my request well. I may be confusing you by saying Peek which implies forward-looking. The behavior I am actually looking for is something like this method from SMA. I am just suggesting to extract this functionality into a trait and implement it where possible.

amv-dev commented 2 years ago

No, your explanation is totally fine. We can use std's Index with indexing by several types, including usize and maybe something like new unit struct LastValue. Some methods already has internal buffer (called Window, like in SMA), so we just need to implement Index<usize> for it. Some methods holds the very last value only (like EMA), so we can implement Index<LastValue> for it. Then it will be possible to add auto-implemented methods (functions) for Method trait:

pub trait Method {
...
    fn last_value(&self) -> Self::Output 
    where Self: Index<LastValue> {
        self[LastValue]
    }

    fn get_previous(&self, index: usize) -> Option<Self::Output>
    where Self: Index<usize> {
        self[index]
    }
...
}

As I said, I need to think how it will be more natural to implement such a feature.

msdrigg commented 2 years ago

I see what you are saying.

Well take your time. I have my wrapper struct that works for me now. Ping me if you want help implementing anything or just want to bounce some ideas off me

amv-dev commented 2 years ago

Well, you can look at my way of implementation of this feature: (https://github.com/amv-dev/yata/pull/21) . I'd like for you to give any suggestions and criticism. It's interesting, that almost every method may implement Peekable by default.

msdrigg commented 2 years ago

Sorry it took me so long to get to this. I had a busy beginning of the week. I'll take a look now

msdrigg commented 2 years ago

Awesome! Thank you so much