wisespace-io / binance-rs

Rust Library for the Binance API
Other
665 stars 297 forks source link

How to save websocket stream to file? File object is out of scope in callback function #11

Closed gregsifr closed 6 years ago

gregsifr commented 6 years ago

The csv crate requires a file object to write to CSV. How can this fileobject be passed/accessed from within a method such as day_ticker_handler? From my understanding the callback parameters are set to: &self, events: &[DayTickerEvent] which means that wtr is out of scope inside day_ticker_handler.

extern crate csv;

let file_path = std::path::Path::new("test.csv");
let mut wtr = csv::Writer::from_path(file_path).unwrap();

Here is a link to day_ticker_handler example in the repository: https://github.com/wisespace-io/binance-rs/blob/master/examples/src/binance_websockets.rs#L115-L118

fn all_trades_websocket() {
    struct WebSocketHandler;

    impl DayTickerEventHandler for WebSocketHandler {
        fn day_ticker_handler(&self, events: &[DayTickerEvent]) {
            for event in events {
                println!(
                    "Symbol: {}, price: {}, qty: {}",
                    event.symbol, event.best_bid, event.best_bid_qty
                );
            }
        }
}
wisespace-io commented 6 years ago

You would just need to implement WebSocketHandler and pass the CSV Object to it, see example below:

fn all_trades_websocket() { 

    struct WebSocketHandler {
        wrt: Writer<File>
    };

    impl WebSocketHandler {
        pub fn new(local_wrt: Writer<File>) -> Self {
            WebSocketHandler {
                wrt: local_wrt
            }
        }

        pub fn write_to_file(&mut self, event: DayTickerEvent) {
            self.wrt.serialize(event);
        }
    }

    impl DayTickerEventHandler for WebSocketHandler {
        fn day_ticker_handler(&mut self, events: &[DayTickerEvent]) {
            for event in events {
                self.write_to_file(event.clone());
                println!(
                    "Symbol: {}, price: {}, qty: {}",
                    event.symbol, event.best_bid, event.best_bid_qty
                );
            }
        }
    }

    let file_path = std::path::Path::new("test.csv");
    let local_wrt = csv::Writer::from_path(file_path).unwrap();

    let web_socket_handler = WebSocketHandler::new(local_wrt);
    let agg_trade: String = format!("!ticker@arr");
    let mut web_socket: WebSockets = WebSockets::new();

    web_socket.add_day_ticker_handler(web_socket_handler);
    web_socket.connect(&agg_trade).unwrap(); // check error
    web_socket.event_loop();
}

However, this code will not compile, unless you change the day_ticker_handler() signature in the DayTickerEventHandler Trait from fn day_ticker_handler(&self, event: &[DayTickerEvent]);

To: fn day_ticker_handler(&mut self, event: &[DayTickerEvent]);

See; https://github.com/wisespace-io/binance-rs/blob/master/src/websockets.rs#L35

And also

https://github.com/wisespace-io/binance-rs/blob/master/src/websockets.rs#L131

 if let Some(ref mut h) = self.ticker_handler {
     h.day_ticker_handler(&trades);
 }
wisespace-io commented 6 years ago

@gregsifr I added a new example to the project as it can be useful to someone else.

https://github.com/wisespace-io/binance-rs/blob/master/examples/src/binance_save_all_trades.rs

It uses a RefCell as the wrt is mutable, so I don't need to change the api interface. However I may change it in the future. I am going to close this issue, okay?

gregsifr commented 6 years ago

Thank you, this is perfect :+1: