crypto-msg-parser 2.9.2

Parse websocket messages from cryptocurreny exchanges
Documentation
mod utils;

const EXCHANGE_NAME: &str = "dydx";

#[cfg(test)]
mod trade {
    use super::EXCHANGE_NAME;
    use crypto_market_type::MarketType;
    use crypto_message::TradeSide;
    use crypto_msg_parser::{extract_symbol, extract_timestamp, parse_trade};

    #[test]
    fn linear_swap() {
        let raw_msg = r#"{"type":"channel_data","connection_id":"c685b690-168e-421d-bfd4-60aae426686d","message_id":2,"id":"BTC-USD","channel":"v3_trades","contents":{"trades":[{"size":"0.124","side":"BUY","price":"56503","createdAt":"2021-10-11T10:36:41.464Z"}]}}"#;
        let trade = &parse_trade(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap()[0];

        crate::utils::check_trade_fields(
            EXCHANGE_NAME,
            MarketType::LinearSwap,
            "BTC/USD".to_string(),
            extract_symbol(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap(),
            trade,
            raw_msg,
        );
        assert_eq!(
            1633948601464,
            extract_timestamp(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap().unwrap()
        );

        assert_eq!(trade.quantity_base, 0.124);
        assert_eq!(trade.quantity_quote, 0.124 * 56503.0);
        assert_eq!(trade.quantity_contract, Some(0.124));

        assert_eq!(trade.side, TradeSide::Buy);
    }
}

#[cfg(test)]
mod l2_event {
    use super::EXCHANGE_NAME;
    use chrono::prelude::*;
    use crypto_market_type::MarketType;
    use crypto_msg_parser::{extract_symbol, extract_timestamp, parse_l2};
    use crypto_msg_type::MessageType;

    #[test]
    fn linear_swap() {
        let raw_msg = r#"{"type":"subscribed","connection_id":"f1e5eecb-7929-4033-8f47-47a2eb71af96","message_id":1,"channel":"v3_orderbook","id":"BTC-USD","contents":{"asks":[{"size":"1.7415","price":"56490"},{"size":"1.7718","price":"56493"}],"bids":[{"size":"1.7088","price":"56489"},{"size":"2.1594","price":"56488"}]}}"#;
        let received_at = Utc::now().timestamp_millis();
        let orderbook =
            &parse_l2(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg, Some(received_at)).unwrap()
                [0];

        assert_eq!(orderbook.asks.len(), 2);
        assert_eq!(orderbook.bids.len(), 2);
        assert!(orderbook.snapshot);

        crate::utils::check_orderbook_fields(
            EXCHANGE_NAME,
            MarketType::LinearSwap,
            MessageType::L2Event,
            "BTC/USD".to_string(),
            extract_symbol(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap(),
            orderbook,
            raw_msg,
        );
        assert_eq!(
            None,
            extract_timestamp(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap()
        );

        assert_eq!(orderbook.timestamp, received_at);

        assert_eq!(orderbook.bids[0].price, 56489.0);
        assert_eq!(orderbook.bids[0].quantity_base, 1.7088);
        assert_eq!(orderbook.bids[0].quantity_quote, 56489.0 * 1.7088);
        assert_eq!(orderbook.bids[0].quantity_contract.unwrap(), 1.7088);

        assert_eq!(orderbook.bids[1].price, 56488.0);
        assert_eq!(orderbook.bids[1].quantity_base, 2.1594);
        assert_eq!(orderbook.bids[1].quantity_quote, 56488.0 * 2.1594);
        assert_eq!(orderbook.bids[1].quantity_contract.unwrap(), 2.1594);

        assert_eq!(orderbook.asks[0].price, 56490.0);
        assert_eq!(orderbook.asks[0].quantity_base, 1.7415);
        assert_eq!(orderbook.asks[0].quantity_quote, 56490.0 * 1.7415);
        assert_eq!(orderbook.asks[0].quantity_contract.unwrap(), 1.7415);

        assert_eq!(orderbook.asks[1].price, 56493.0);
        assert_eq!(orderbook.asks[1].quantity_base, 1.7718);
        assert_eq!(orderbook.asks[1].quantity_quote, 56493.0 * 1.7718);
        assert_eq!(orderbook.asks[1].quantity_contract.unwrap(), 1.7718);

        let raw_msg = r#"{"type":"channel_data","connection_id":"f1e5eecb-7929-4033-8f47-47a2eb71af96","message_id":2,"id":"BTC-USD","channel":"v3_orderbook","contents":{"offset":"2060907065","bids":[],"asks":[["56525","0.4782"],["56527","0.0186"]]}}"#;
        let orderbook =
            &parse_l2(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg, Some(1633951152106)).unwrap()
                [0];

        assert_eq!(orderbook.asks.len(), 2);
        assert_eq!(orderbook.bids.len(), 0);
        assert!(!orderbook.snapshot);

        crate::utils::check_orderbook_fields(
            EXCHANGE_NAME,
            MarketType::LinearSwap,
            MessageType::L2Event,
            "BTC/USD".to_string(),
            extract_symbol(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap(),
            orderbook,
            raw_msg,
        );

        assert_eq!(orderbook.timestamp, 1633951152106);

        assert_eq!(orderbook.asks[0].price, 56525.0);
        assert_eq!(orderbook.asks[0].quantity_base, 0.4782);
        assert_eq!(orderbook.asks[0].quantity_quote, 56525.0 * 0.4782);
        assert_eq!(orderbook.asks[0].quantity_contract.unwrap(), 0.4782);
    }
}

#[cfg(test)]
mod l2_snapshot {
    use super::EXCHANGE_NAME;
    use crypto_market_type::MarketType;
    use crypto_msg_parser::{extract_symbol, extract_timestamp};

    #[test]
    fn linear_swap() {
        let raw_msg = r#"{"asks":[{"size":"0.595","price":"30315"},{"size":"1.56","price":"30317"},{"size":"0.345","price":"30318"}],"bids":[{"size":"1.3529","price":"30310"},{"size":"4.0488","price":"30308"},{"size":"0.033","price":"30306"}]}"#;

        assert_eq!("NONE", extract_symbol(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap());

        assert_eq!(
            None,
            extract_timestamp(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap()
        );
    }
}

#[cfg(test)]
mod open_interest {
    use super::EXCHANGE_NAME;
    use crypto_market_type::MarketType;
    use crypto_msg_parser::{extract_symbol, extract_timestamp};

    #[test]
    fn linear_swap() {
        let raw_msg = r#"{"markets":{"BTC-USD":{"market":"BTC-USD","status":"ONLINE","baseAsset":"BTC","quoteAsset":"USD","stepSize":"0.0001","tickSize":"1","indexPrice":"29718.5600","oraclePrice":"29686.8200","priceChange24H":"-3.120000","nextFundingRate":"0.0000077940","nextFundingAt":"2022-06-04T12:00:00.000Z","minOrderSize":"0.001","type":"PERPETUAL","initialMarginFraction":"0.05","maintenanceMarginFraction":"0.03","volume24H":"172496250.187000","trades24H":"27100","openInterest":"7989.6723","incrementalInitialMarginFraction":"0.01","incrementalPositionSize":"1.5","maxPositionSize":"170","baselinePositionSize":"9","assetResolution":"10000000000","syntheticAssetId":"0x4254432d3130000000000000000000"},"AVAX-USD":{"market":"AVAX-USD","status":"ONLINE","baseAsset":"AVAX","quoteAsset":"USD","stepSize":"0.1","tickSize":"0.01","indexPrice":"23.1026","oraclePrice":"23.0900","priceChange24H":"0.442564","nextFundingRate":"0.0000073995","nextFundingAt":"2022-06-04T12:00:00.000Z","minOrderSize":"1","type":"PERPETUAL","initialMarginFraction":"0.10","maintenanceMarginFraction":"0.05","volume24H":"17097633.955000","trades24H":"6889","openInterest":"988005.4","incrementalInitialMarginFraction":"0.02","incrementalPositionSize":"1800","maxPositionSize":"91000","baselinePositionSize":"9000","assetResolution":"10000000","syntheticAssetId":"0x415641582d37000000000000000000"}}}"#;

        assert_eq!("ALL", extract_symbol(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap());

        assert_eq!(
            None,
            extract_timestamp(EXCHANGE_NAME, MarketType::LinearSwap, raw_msg).unwrap()
        );
    }
}