use digdigdig3::core::traits::Credentials;
use digdigdig3::core::types::{AccountType, ExchangeId, SymbolInfo};
use digdigdig3::core::websocket::KlineInterval;
use crate::data::{
AggTradePoint, BalanceUpdatePoint, BarPoint, BasisPoint, BlockTradePoint, CompositeIndexPoint,
FootprintPoint, FundingRatePoint, FundingSettlementPoint, HistoricalVolatilityPoint,
IndexPriceKlinePoint, IndexPricePoint, InsuranceFundPoint, LiquidationPoint,
LongShortRatioPoint, MarkPriceKlinePoint, MarkPricePoint,
MarketWarningPoint, ObDeltaPoint, ObSnapshotPoint, OpenInterestPoint, OptionGreeksPoint,
OrderUpdatePoint, OrderbookL3Point, PositionUpdatePoint, PredictedFundingPoint,
PremiumIndexKlinePoint, RiskLimitPoint,
SettlementEventPoint, TickerPoint, TradePoint, VolatilityIndexPoint,
};
use crate::series::{Kind, SeriesKey};
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Stream {
Ticker,
Trade,
Orderbook,
OrderbookDelta,
Kline(KlineInterval),
MarkPrice,
FundingRate,
OpenInterest,
Liquidation,
AggTrade,
BlockTrade,
IndexPrice,
CompositeIndex,
OptionGreeks,
VolatilityIndex,
HistoricalVolatility,
LongShortRatio,
Basis,
InsuranceFund,
OrderbookL3,
SettlementEvent,
MarketWarning,
RiskLimit,
PredictedFunding,
FundingSettlement,
MarkPriceKline(KlineInterval),
IndexPriceKline(KlineInterval),
PremiumIndexKline(KlineInterval),
RangeBar(u64),
TickBar(u32),
VolumeBar(u64),
Footprint(KlineInterval),
OrderUpdate,
BalanceUpdate,
PositionUpdate,
}
impl Stream {
pub(crate) fn to_kind(&self) -> Kind {
match self {
Stream::Trade => Kind::Trade,
Stream::AggTrade => Kind::AggTrade,
Stream::Kline(iv) => Kind::Kline(iv.clone()),
Stream::Ticker => Kind::Ticker,
Stream::Orderbook => Kind::Orderbook,
Stream::OrderbookDelta => Kind::OrderbookDelta,
Stream::MarkPrice => Kind::MarkPrice,
Stream::FundingRate => Kind::FundingRate,
Stream::OpenInterest => Kind::OpenInterest,
Stream::Liquidation => Kind::Liquidation,
Stream::BlockTrade => Kind::BlockTrade,
Stream::IndexPrice => Kind::IndexPrice,
Stream::CompositeIndex => Kind::CompositeIndex,
Stream::OptionGreeks => Kind::OptionGreeks,
Stream::VolatilityIndex => Kind::VolatilityIndex,
Stream::HistoricalVolatility => Kind::HistoricalVolatility,
Stream::LongShortRatio => Kind::LongShortRatio,
Stream::Basis => Kind::Basis,
Stream::InsuranceFund => Kind::InsuranceFund,
Stream::OrderbookL3 => Kind::OrderbookL3,
Stream::SettlementEvent => Kind::SettlementEvent,
Stream::MarketWarning => Kind::MarketWarning,
Stream::RiskLimit => Kind::RiskLimit,
Stream::PredictedFunding => Kind::PredictedFunding,
Stream::FundingSettlement => Kind::FundingSettlement,
Stream::MarkPriceKline(iv) => Kind::MarkPriceKline(iv.clone()),
Stream::IndexPriceKline(iv) => Kind::IndexPriceKline(iv.clone()),
Stream::PremiumIndexKline(iv) => Kind::PremiumIndexKline(iv.clone()),
Stream::RangeBar(r) => Kind::RangeBar(*r),
Stream::TickBar(n) => Kind::TickBar(*n),
Stream::VolumeBar(v) => Kind::VolumeBar(*v),
Stream::Footprint(iv) => Kind::Footprint(iv.clone()),
Stream::OrderUpdate => Kind::OrderUpdate,
Stream::BalanceUpdate => Kind::BalanceUpdate,
Stream::PositionUpdate => Kind::PositionUpdate,
}
}
pub fn is_private(&self) -> bool {
matches!(self, Stream::OrderUpdate | Stream::BalanceUpdate | Stream::PositionUpdate)
}
}
#[derive(Debug, Clone)]
pub(crate) struct Entry {
pub(crate) exchange: ExchangeId,
pub(crate) symbol: String,
pub(crate) account_type: AccountType,
pub(crate) streams: Vec<Stream>,
pub(crate) is_raw: bool,
pub(crate) credentials: Option<Credentials>,
}
#[derive(Debug, Default, Clone)]
pub struct SubscriptionSet {
pub(crate) entries: Vec<Entry>,
}
impl SubscriptionSet {
pub fn new() -> Self { Self::default() }
pub fn add(
mut self,
exchange: ExchangeId,
symbol: impl Into<String>,
account_type: AccountType,
streams: impl IntoIterator<Item = Stream>,
) -> Self {
self.entries.push(Entry {
exchange,
symbol: symbol.into(),
account_type,
streams: streams.into_iter().collect(),
is_raw: false,
credentials: None,
});
self
}
pub fn add_raw(
mut self,
exchange: ExchangeId,
symbol: impl Into<String>,
account_type: AccountType,
streams: impl IntoIterator<Item = Stream>,
) -> Self {
self.entries.push(Entry {
exchange,
symbol: symbol.into(),
account_type,
streams: streams.into_iter().collect(),
is_raw: true,
credentials: None,
});
self
}
pub fn add_authenticated(
mut self,
exchange: ExchangeId,
account_type: AccountType,
credentials: Credentials,
streams: impl IntoIterator<Item = Stream>,
) -> Self {
self.entries.push(Entry {
exchange,
symbol: String::new(),
account_type,
streams: streams.into_iter().collect(),
is_raw: true,
credentials: Some(credentials),
});
self
}
pub fn len(&self) -> usize { self.entries.len() }
pub fn is_empty(&self) -> bool { self.entries.is_empty() }
}
#[derive(Debug, Clone)]
pub enum Event {
Trade {
exchange: ExchangeId,
symbol: String,
point: TradePoint,
},
AggTrade {
exchange: ExchangeId,
symbol: String,
point: AggTradePoint,
},
Bar {
exchange: ExchangeId,
symbol: String,
timeframe: KlineInterval,
point: BarPoint,
},
Ticker {
exchange: ExchangeId,
symbol: String,
point: TickerPoint,
},
OrderbookSnapshot {
exchange: ExchangeId,
symbol: String,
point: ObSnapshotPoint,
},
OrderbookDelta {
exchange: ExchangeId,
symbol: String,
point: ObDeltaPoint,
},
MarkPrice {
exchange: ExchangeId,
symbol: String,
point: MarkPricePoint,
},
FundingRate {
exchange: ExchangeId,
symbol: String,
point: FundingRatePoint,
},
OpenInterest {
exchange: ExchangeId,
symbol: String,
point: OpenInterestPoint,
},
Liquidation {
exchange: ExchangeId,
symbol: String,
point: LiquidationPoint,
},
BlockTrade {
exchange: ExchangeId,
symbol: String,
point: BlockTradePoint,
},
IndexPrice {
exchange: ExchangeId,
symbol: String,
point: IndexPricePoint,
},
CompositeIndex {
exchange: ExchangeId,
symbol: String,
point: CompositeIndexPoint,
},
OptionGreeks {
exchange: ExchangeId,
symbol: String,
point: OptionGreeksPoint,
},
VolatilityIndex {
exchange: ExchangeId,
symbol: String,
point: VolatilityIndexPoint,
},
HistoricalVolatility {
exchange: ExchangeId,
symbol: String,
point: HistoricalVolatilityPoint,
},
LongShortRatio {
exchange: ExchangeId,
symbol: String,
point: LongShortRatioPoint,
},
Basis {
exchange: ExchangeId,
symbol: String,
point: BasisPoint,
},
InsuranceFund {
exchange: ExchangeId,
symbol: String,
point: InsuranceFundPoint,
},
OrderbookL3 {
exchange: ExchangeId,
symbol: String,
point: OrderbookL3Point,
},
SettlementEvent {
exchange: ExchangeId,
symbol: String,
point: SettlementEventPoint,
},
MarketWarning {
exchange: ExchangeId,
symbol: String,
point: MarketWarningPoint,
},
RiskLimit {
exchange: ExchangeId,
symbol: String,
point: RiskLimitPoint,
},
PredictedFunding {
exchange: ExchangeId,
symbol: String,
point: PredictedFundingPoint,
},
FundingSettlement {
exchange: ExchangeId,
symbol: String,
point: FundingSettlementPoint,
},
MarkPriceKline {
exchange: ExchangeId,
symbol: String,
timeframe: KlineInterval,
point: MarkPriceKlinePoint,
},
IndexPriceKline {
exchange: ExchangeId,
symbol: String,
timeframe: KlineInterval,
point: IndexPriceKlinePoint,
},
PremiumIndexKline {
exchange: ExchangeId,
symbol: String,
timeframe: KlineInterval,
point: PremiumIndexKlinePoint,
},
Footprint {
exchange: ExchangeId,
symbol: String,
point: FootprintPoint,
},
ConnectorReady {
exchange: ExchangeId,
},
SymbolsLoaded {
exchange: ExchangeId,
account_type: AccountType,
symbols: Vec<SymbolInfo>,
},
OrderUpdate {
exchange: ExchangeId,
account_type: AccountType,
symbol: String,
point: OrderUpdatePoint,
},
BalanceUpdate {
exchange: ExchangeId,
account_type: AccountType,
symbol: String,
point: BalanceUpdatePoint,
},
PositionUpdate {
exchange: ExchangeId,
account_type: AccountType,
symbol: String,
point: PositionUpdatePoint,
},
}
impl Event {
pub fn exchange(&self) -> ExchangeId {
match self {
Event::Trade { exchange, .. } | Event::AggTrade { exchange, .. } |
Event::Bar { exchange, .. } | Event::Ticker { exchange, .. } |
Event::OrderbookSnapshot { exchange, .. } | Event::OrderbookDelta { exchange, .. } |
Event::MarkPrice { exchange, .. } |
Event::FundingRate { exchange, .. } | Event::OpenInterest { exchange, .. } |
Event::Liquidation { exchange, .. } |
Event::BlockTrade { exchange, .. } | Event::IndexPrice { exchange, .. } |
Event::CompositeIndex { exchange, .. } | Event::OptionGreeks { exchange, .. } |
Event::VolatilityIndex { exchange, .. } | Event::HistoricalVolatility { exchange, .. } |
Event::LongShortRatio { exchange, .. } |
Event::Basis { exchange, .. } | Event::InsuranceFund { exchange, .. } |
Event::OrderbookL3 { exchange, .. } | Event::SettlementEvent { exchange, .. } |
Event::MarketWarning { exchange, .. } |
Event::RiskLimit { exchange, .. } | Event::PredictedFunding { exchange, .. } |
Event::FundingSettlement { exchange, .. } |
Event::MarkPriceKline { exchange, .. } | Event::IndexPriceKline { exchange, .. } |
Event::PremiumIndexKline { exchange, .. } |
Event::Footprint { exchange, .. } => *exchange,
Event::OrderUpdate { exchange, .. } | Event::BalanceUpdate { exchange, .. } |
Event::PositionUpdate { exchange, .. } => *exchange,
Event::ConnectorReady { exchange } => *exchange,
Event::SymbolsLoaded { exchange, .. } => *exchange,
}
}
pub fn symbol(&self) -> &str {
match self {
Event::Trade { symbol, .. } | Event::AggTrade { symbol, .. } |
Event::Bar { symbol, .. } | Event::Ticker { symbol, .. } |
Event::OrderbookSnapshot { symbol, .. } | Event::OrderbookDelta { symbol, .. } |
Event::MarkPrice { symbol, .. } |
Event::FundingRate { symbol, .. } | Event::OpenInterest { symbol, .. } |
Event::Liquidation { symbol, .. } |
Event::BlockTrade { symbol, .. } | Event::IndexPrice { symbol, .. } |
Event::CompositeIndex { symbol, .. } | Event::OptionGreeks { symbol, .. } |
Event::VolatilityIndex { symbol, .. } | Event::HistoricalVolatility { symbol, .. } |
Event::LongShortRatio { symbol, .. } |
Event::Basis { symbol, .. } | Event::InsuranceFund { symbol, .. } |
Event::OrderbookL3 { symbol, .. } | Event::SettlementEvent { symbol, .. } |
Event::MarketWarning { symbol, .. } |
Event::RiskLimit { symbol, .. } | Event::PredictedFunding { symbol, .. } |
Event::FundingSettlement { symbol, .. } |
Event::MarkPriceKline { symbol, .. } | Event::IndexPriceKline { symbol, .. } |
Event::PremiumIndexKline { symbol, .. } |
Event::Footprint { symbol, .. } => symbol,
Event::OrderUpdate { symbol, .. } | Event::BalanceUpdate { symbol, .. } |
Event::PositionUpdate { symbol, .. } => symbol,
Event::ConnectorReady { .. } | Event::SymbolsLoaded { .. } => "",
}
}
pub(crate) fn set_symbol(&mut self, new_symbol: String) {
match self {
Event::Trade { symbol, .. }
| Event::AggTrade { symbol, .. }
| Event::Bar { symbol, .. }
| Event::Ticker { symbol, .. }
| Event::OrderbookSnapshot { symbol, .. }
| Event::OrderbookDelta { symbol, .. }
| Event::MarkPrice { symbol, .. }
| Event::FundingRate { symbol, .. }
| Event::OpenInterest { symbol, .. }
| Event::Liquidation { symbol, .. }
| Event::BlockTrade { symbol, .. }
| Event::IndexPrice { symbol, .. }
| Event::CompositeIndex { symbol, .. }
| Event::OptionGreeks { symbol, .. }
| Event::VolatilityIndex { symbol, .. }
| Event::HistoricalVolatility { symbol, .. }
| Event::LongShortRatio { symbol, .. }
| Event::Basis { symbol, .. }
| Event::InsuranceFund { symbol, .. }
| Event::OrderbookL3 { symbol, .. }
| Event::SettlementEvent { symbol, .. }
| Event::MarketWarning { symbol, .. }
| Event::RiskLimit { symbol, .. }
| Event::PredictedFunding { symbol, .. }
| Event::FundingSettlement { symbol, .. }
| Event::MarkPriceKline { symbol, .. }
| Event::IndexPriceKline { symbol, .. }
| Event::PremiumIndexKline { symbol, .. }
| Event::Footprint { symbol, .. }
| Event::OrderUpdate { symbol, .. }
| Event::BalanceUpdate { symbol, .. }
| Event::PositionUpdate { symbol, .. } => *symbol = new_symbol,
Event::ConnectorReady { .. } | Event::SymbolsLoaded { .. } => {}
}
}
pub fn timestamp_ms(&self) -> i64 {
use crate::series::DataPoint;
match self {
Event::Trade { point, .. } => point.timestamp_ms(),
Event::AggTrade { point, .. } => point.timestamp_ms(),
Event::Bar { point, .. } => point.timestamp_ms(),
Event::Ticker { point, .. } => point.timestamp_ms(),
Event::OrderbookSnapshot { point, .. } => point.timestamp_ms(),
Event::OrderbookDelta { point, .. } => point.timestamp_ms(),
Event::MarkPrice { point, .. } => point.timestamp_ms(),
Event::FundingRate { point, .. } => point.timestamp_ms(),
Event::OpenInterest { point, .. } => point.timestamp_ms(),
Event::Liquidation { point, .. } => point.timestamp_ms(),
Event::BlockTrade { point, .. } => point.timestamp_ms(),
Event::IndexPrice { point, .. } => point.timestamp_ms(),
Event::CompositeIndex { point, .. } => point.timestamp_ms(),
Event::OptionGreeks { point, .. } => point.timestamp_ms(),
Event::VolatilityIndex { point, .. } => point.timestamp_ms(),
Event::HistoricalVolatility { point, .. } => point.timestamp_ms(),
Event::LongShortRatio { point, .. } => point.timestamp_ms(),
Event::Basis { point, .. } => point.timestamp_ms(),
Event::InsuranceFund { point, .. } => point.timestamp_ms(),
Event::OrderbookL3 { point, .. } => point.timestamp_ms(),
Event::SettlementEvent { point, .. } => point.timestamp_ms(),
Event::MarketWarning { point, .. } => point.timestamp_ms(),
Event::RiskLimit { point, .. } => point.timestamp_ms(),
Event::PredictedFunding { point, .. } => point.timestamp_ms(),
Event::FundingSettlement { point, .. } => point.timestamp_ms(),
Event::MarkPriceKline { point, .. } => point.timestamp_ms(),
Event::IndexPriceKline { point, .. } => point.timestamp_ms(),
Event::PremiumIndexKline { point, .. } => point.timestamp_ms(),
Event::Footprint { point, .. } => point.timestamp_ms(),
Event::OrderUpdate { point, .. } => point.timestamp_ms(),
Event::BalanceUpdate { point, .. } => point.timestamp_ms(),
Event::PositionUpdate { point, .. } => point.timestamp_ms(),
Event::ConnectorReady { .. } | Event::SymbolsLoaded { .. } => {
chrono::Utc::now().timestamp_millis()
}
}
}
}
#[derive(Debug, Clone)]
pub struct WarmupReport {
pub ok: Vec<ExchangeId>,
pub failed: Vec<(ExchangeId, String)>,
}
pub struct SubscriptionHandle {
pub(crate) rx: tokio::sync::mpsc::UnboundedReceiver<Event>,
pub(crate) _refs: Vec<MultiplexRef>,
}
impl std::fmt::Debug for SubscriptionHandle {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("SubscriptionHandle").finish()
}
}
impl SubscriptionHandle {
pub async fn recv(&mut self) -> Option<Event> {
self.rx.recv().await
}
}
#[derive(Debug)]
pub struct FailedStream {
pub exchange: ExchangeId,
pub account_type: AccountType,
pub symbol: String,
pub stream: Stream,
pub error: crate::StationError,
}
pub struct SubscribeReport {
pub handle: SubscriptionHandle,
pub ok: Vec<SeriesKey>,
pub failed: Vec<FailedStream>,
}
impl SubscribeReport {
pub fn is_fully_ok(&self) -> bool { self.failed.is_empty() }
pub fn total(&self) -> usize { self.ok.len() + self.failed.len() }
pub(crate) fn take_refs_into(mut self, dest: &mut Vec<MultiplexRef>) -> Self {
dest.extend(std::mem::take(&mut self.handle._refs));
self
}
}
impl std::fmt::Debug for SubscribeReport {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("SubscribeReport")
.field("ok", &self.ok.len())
.field("failed", &self.failed.len())
.finish()
}
}
pub(crate) struct MultiplexRef {
pub(crate) station: std::sync::Weak<crate::station::StationInner>,
pub(crate) key: SeriesKey,
}
impl Drop for MultiplexRef {
fn drop(&mut self) {
if let Some(inner) = self.station.upgrade() {
inner.release_consumer(&self.key);
}
}
}