Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Latest trade data #43

Closed
wants to merge 1 commit into from
Closed

Latest trade data #43

wants to merge 1 commit into from

Conversation

sbeam
Copy link

@sbeam sbeam commented Oct 24, 2022

This uses the Latest Multi Trades endpoint to get the latest trade data for one or more symbols at once. This was heavily copied from the last_quote mod, but changed to deal with the JSON response as nested objects. I elected to return a vec of Trades with the symbol attached because it suits my needs. closes #42

@d-e-s-o
Copy link
Owner

d-e-s-o commented Oct 25, 2022

Nice! Thanks! I will take a closer look later this week, but one quick thought: Instead of copying the last_quote module to last_trade and then modifying it to work with multiple symbols, would you be up for modifying last_quote to gain multi symbol support first? In my opnion it's more universal, so I don't see a downside. Last I checked I recall that there was a similar multi symbol endpoint there.

@sbeam
Copy link
Author

sbeam commented Oct 25, 2022

yes that would make sense, they are similar and both have a single symbol endpoint and multi. However the last_quote currently returns a single Quote, and changing it to a Vec would be breaking. Maybe would be best to have last_quote, last_quote_multi, last_trade and last_trade_multi? So all is nice and consistent?

@d-e-s-o
Copy link
Owner

d-e-s-o commented Oct 26, 2022

yes that would make sense, they are similar and both have a single symbol endpoint and multi. However the last_quote currently returns a single Quote, and changing it to a Vec would be breaking.

But to be honest, backwards compatibility is not much of a concern for me at this point. The API surface is too large to nail everything early on, enabling more without a need is a maintenance burden, and stuff is changing upstream. So don't worry about it, we just bump the crate's version with the next release.

Maybe would be best to have last_quote, last_quote_multi, last_trade and last_trade_multi? So all is nice and consistent?

It's an option, yeah. From my perspective, though, one is basically a superset of the other and so we may as well opt for the fewer-lines-of-code option and just stick with the multi versions of both.

@sbeam
Copy link
Author

sbeam commented Oct 31, 2022

got it. I'll work on this at some point this week

@sbeam
Copy link
Author

sbeam commented Nov 3, 2022

@d-e-s-o ok, see what you think. I wanted to use this library in my project to learn Rust and it's been very helpful in that regard! To reduce the copy/paste factor, chose to implement a couple generic traits to pull the data objects out of the json -- maybe not worth the trouble but it works. Also added examples etc

Copy link
Owner

@d-e-s-o d-e-s-o left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the delay.

@d-e-s-o ok, see what you think. I wanted to use this library in my project to learn Rust and it's been very helpful in that regard! To reduce the copy/paste factor, chose to implement a couple generic traits to pull the data objects out of the json -- maybe not worth the trouble but it works. Also added examples etc

Yeah, I'd say let's not add the trait. It doesn't really add value from my perspective and just complicates things. I'd also suggest we keep the pull request concentrated on the plan we laid out earlier.

Cargo.toml Outdated
Comment on lines 27 to 32
[[example]]
name = "order"

[[example]]
name = "stream-realtime-data"

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please create a separate commit for these changes?

@@ -8,9 +8,14 @@ mod unfold;
pub mod bars;
/// Functionality for retrieval of the most recent quote.
pub mod last_quote;
/// Functionality for retrieval of the most recent trade(s).
pub mod latest_trade;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we calling one "last" and the other "latest"? Seems inconsistent.

let api_info = ApiInfo::from_env().unwrap();
let client = Client::new(api_info);

let req = LastQuoteReq::new("SPY,QQQ,MSFT");
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should be passing in some kind of pre-formatted string. It should likely be a vec/iter/slice/whatever of strings. If I recall correctly there is precedent in other parts of the API surface that we should follow, unless not suitable for some reason.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's what alpaca wants, but I agree it's a bit icky. will fix

Add support for Latest Multi Trades endpoint to get the latest trade
data for one or more symbols in one call. For consistency, also
converted
the existing latest_quote mod to also fetch and represent multiple
symbols at once.
@sbeam
Copy link
Author

sbeam commented Nov 15, 2022

@d-e-s-o ok, updated as requested and squashed

@d-e-s-o
Copy link
Owner

d-e-s-o commented Nov 17, 2022

@d-e-s-o ok, updated as requested and squashed

Thank you! Will have reviewed by the end of the weekend the latest.

Copy link
Owner

@d-e-s-o d-e-s-o left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I won't be able to land this code without major modifications and I don't have the time to write 2+ hour reviews for each iteration, which is pretty much guaranteed to annoy the both of us.

My suggestion is that you create a pull request for the changes to the last_quote module first (renaming it to last_quotes in the process and addressing the comments I left there). We get that in. Then we work on the rest.

I expect you to understand existing code and why it does what it does or at least accept that it is there for a reason and not change it randomly, though, please. The general guidance for open source contributions to be accepted is to mirror existing project patterns, styles, etc. I am happy to explain/fix minor things, but I don't have the time or nerves to rework changes that make no attempt at blending in or doing research on existing patterns.

Edit: Of course also no hard feelings if you don't want to embark on this process or disagree with my stance.

/// A helper for initializing [`LastQuoteReq`] objects.
#[derive(Clone, Debug, Default, Eq, PartialEq)]
#[allow(missing_copy_implementations)]
pub struct LastQuoteReqInit {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see a good reason why this type is being removed?

// TODO: Not all fields are hooked up.
#[derive(Clone, Debug, Deserialize, Eq, PartialEq)]
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this change necessary?

#[non_exhaustive]
pub struct Quote {
/// The time stamp of this quote.
#[serde(rename = "t")]
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are these renames being removed?

/// A representation of the JSON data in the response
#[derive(Debug, Deserialize)]
pub struct LastQuoteResponse {
quotes: HashMap<String, QuoteDataPoint>,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why a HashMap repesentation? We should likely expose what we get.

fn path(input: &Self::Input) -> Str {
format!("/v2/stocks/{}/quotes/latest", input.symbol).into()
fn path(_input: &Self::Input) -> Str {
format!("/v2/stocks/quotes/latest").into()
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't need to format if you are not formatting.

}

fn parse_err(body: &[u8]) -> Result<Self::ApiError, Vec<u8>> {
from_json::<Self::ApiError>(body).map_err(|_| body.to_vec())
}
}


Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keep needless useless changes to a minimum?


let quote = from_json::<Quote>(response).unwrap();
"quotes": {
"TSLA": {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please no tabs in code using spaces?

@sbeam
Copy link
Author

sbeam commented Nov 23, 2022

When you mentioned that back-compat wasn't a concern, I took that as more license to refactor than it seems you intended. I understand your points and appreciate the concern for quality and following the prior patterns.

Most of these changes were to make it work with the multiple quotes JSON, which has a different structure than the single quote response. So the way the response is deserialized and coerced into a Vec<Quote> had to be much different, and that was the best way I found to do it. However, we don't have to return a Vec<Quote>, it could be a HashMap<String, Quote>, which would be exactly what the JSON looks like and therefore simpler to implement.

That said, I'm most interested in getting the Last Trade part of this in. Would it be more agreeable to go back to the original plan, and copy the existing pattern into last_trade, using the single object API instead of multi? There is no reason we have to implement multi here -- it was kind of a "bonus" in my mind -- but it could be done as part of an followup later on.

@d-e-s-o
Copy link
Owner

d-e-s-o commented Nov 24, 2022

That said, I'm most interested in getting the Last Trade part of this in. Would it be more agreeable to go back to the original plan, and copy the existing pattern into last_trade, using the single object API instead of multi? There is no reason we have to implement multi here -- it was kind of a "bonus" in my mind -- but it could be done as part of an followup later on.

In a way I coerced you into doing the last quote multi conversion, so perhaps we can do the following: I can take a closer look at getting last_quote converted into last_quotes in the next few days. Then you can build the last trade data retrieval in a similar vein. That should eliminate some of the guess work on your end and a bunch of communication overhead on mine and you can focus on the part you have an interest in. Does that sound reasonable?

@sbeam
Copy link
Author

sbeam commented Nov 24, 2022

Yes, whichever way you want to go is fine of course. If you don't have time to convert this to multi then I'd be happy to put up another PR that just implements last_trade (single) and doesn't touch anything else.

@d-e-s-o
Copy link
Owner

d-e-s-o commented Nov 24, 2022

Let me take a look tomorrow and then we'll take it from there.

@d-e-s-o
Copy link
Owner

d-e-s-o commented Nov 25, 2022

Let me take a look tomorrow and then we'll take it from there.

Okay, it's mostly ready at https://github.com/d-e-s-o/apca/tree/topic/last-quote-multi. Will probably land that tomorrow and don't expect many mor echanges.

Edit: The changes are now in devel and I've deleted the aforementioned branch.

@d-e-s-o
Copy link
Owner

d-e-s-o commented Jun 18, 2023

Closing this pull request as it hasn't seen any response or update.

@d-e-s-o d-e-s-o closed this Jun 18, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

support for Latest Multi Trades
2 participants