wboayue / rust-ibapi

An implementation of the Interactive Brokers API for Rust
MIT License
45 stars 21 forks source link

Client::connect fails on parse_connection_time #101

Closed BrettForr closed 1 year ago

BrettForr commented 1 year ago

Summary:

When I try to connect to the client, the program panics on parsing the connection time.

Strangely, this was working fine for me a couple days ago; I was able to connect to the client and pull some historical data. But when I tried to rerun my program today I started getting this error. I'm new to this crate (and new to rust), so it's very possible I'm missing something obvious.

Steps to reproduce

Running this

fn main() {
    let client = Client::connect("127.0.0.1:4002", 100).unwrap();

    println!("Connected to client");
}

produces the error

thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: ParseFromDescription(InvalidComponent("year"))', /home/brett/.cargo/registry/s
rc/index.crates.io-6f17d22bba15001f/ibapi-0.3.0/src/client.rs:963:102

It's failing on the date below

fn parse_connection_time(connection_time: &str) -> (OffsetDateTime, &'static Tz) {
    let parts: Vec<&str> = connection_time.split(' ').collect();

    let zones = timezones::find_by_name(parts[2]);

    let format = format_description!("[year][month][day] [hour]:[minute]:[second]");
    println!("Time parts are: {} {} {}", parts[0], parts[1], parts[2]);
    let date = time::PrimitiveDateTime::parse(format!("{} {}", parts[0], parts[1]).as_str(), format).unwrap();

As far as I can tell, the date time it's trying to parse is in the correct format though. I added some println and parts looks as expected: 20230730 23:30:02 EST

Environment

I'm running IB Gateway 10.19. I'm getting the error when trying to connect to both the live and paper accounts.

name = "ibapi"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b54ef0f85ed49cba2635082cfa47bb050211481104036ce28d255de3e79484e6"
BrettForr commented 1 year ago

I tested a version where I changed the date part of the string to the format [year] [month] [day] and it seems to be working:

fn parse_connection_time(connection_time: &str) -> (OffsetDateTime, &'static Tz) {
    let parts: Vec<&str> = connection_time.split(' ').collect();

    let zones = timezones::find_by_name(parts[2]);

    let year = &parts[0][0..4];
    let month = &parts[0][4..6];
    let day = &parts[0][6..8];

    let format = format_description!("[year] [month] [day] [hour]:[minute]:[second]");
    let date_string = format!("{} {} {} {}", year, month, day, parts[1]);
    let date = time::PrimitiveDateTime::parse(&date_string, format).unwrap();
    let timezone = zones[0];
    match date.assume_timezone(timezone) {
        OffsetResult::Some(date) => (date, timezone),
        _ => (OffsetDateTime::now_utc(), time_tz::timezones::db::UTC),
    }
}
wboayue commented 1 year ago

That's strange. I'll see if I can reproduce.

BrettForr commented 1 year ago

I spent some more time trying to bottom out what it is, or at least how to reproduce more precisely. I also was using some other crates in this project, including mongodb. It seems that including mongodb in my project produces the error when connecting to the client.

So running the example program above, but with this Cargo.toml produces the error

[dependencies]
ibapi = "0.3.0"
mongodb = "2.6.0"

but connecting to the client works as expected if I drop the mongodb dependency.

Any ideas on why this would happen? The time specification in my Cargo.lock appears to be the same regardless of whether I include mongodb or not. Maybe one of the dependencies for time is different and that gets used somewhere in the chain of the parse function?

[[package]]
name = "time"
version = "0.3.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b79eabcd964882a646b3584543ccabeae7869e9ac32a46f6f22b7a5bd405308b"
dependencies = [
 "deranged",
 "itoa",
 "libc",
 "num_threads",
 "serde",
 "time-core",
 "time-macros",
]
wboayue commented 1 year ago

Released a new version 0.4.0. Failure to parse server time is no longer a connection failure. I most cases the timezone should will be captured. Timezone is used when parsing dates for historical bars.