Skip to content

Commit 0aa7f7f

Browse files
committed
Refine request_funding_rates and add test coverage
- Fix request_funding_rates calling request_trades instead of itself - Fix docstring typos (trades -> funding rates) in actor.rs/.pyx - Replace todo!() panics with proper errors in Postgres cache adapter - Add request_funding_rates tests for actor, data client, and engine - Add on_historical_funding_rates to TestDataActor for proper recording - Add request_funding_rates to MockDataClient (Rust and Python)
1 parent d317909 commit 0aa7f7f

File tree

11 files changed

+227
-28
lines changed

11 files changed

+227
-28
lines changed

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/common/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ iai = { workspace = true }
9090
proptest = { workspace = true }
9191
rand = { workspace = true }
9292
regex = { workspace = true }
93+
rust_decimal = { workspace = true }
94+
rust_decimal_macros = { workspace = true }
9395
tempfile = { workspace = true }
9496

9597
[build-dependencies]

crates/common/src/actor/data_actor.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -497,13 +497,16 @@ pub trait DataActor:
497497
Ok(())
498498
}
499499

500-
/// Actions to be performed when receiving historical trades.
500+
/// Actions to be performed when receiving historical funding rates.
501501
///
502502
/// # Errors
503503
///
504-
/// Returns an error if handling the historical trades fails.
504+
/// Returns an error if handling the historical funding rates fails.
505505
#[allow(unused_variables)]
506-
fn on_historical_funding_rates(&mut self, trades: &[FundingRateUpdate]) -> anyhow::Result<()> {
506+
fn on_historical_funding_rates(
507+
&mut self,
508+
funding_rates: &[FundingRateUpdate],
509+
) -> anyhow::Result<()> {
507510
Ok(())
508511
}
509512

@@ -1892,7 +1895,7 @@ pub trait DataActor:
18921895
get_actor_unchecked::<Self>(&actor_id).handle_funding_rates_response(resp);
18931896
});
18941897

1895-
DataActorCore::request_trades(
1898+
DataActorCore::request_funding_rates(
18961899
self,
18971900
instrument_id,
18981901
start,
@@ -3765,7 +3768,7 @@ impl DataActorCore {
37653768
Ok(request_id)
37663769
}
37673770

3768-
/// Helper method for requesting trades.
3771+
/// Helper method for requesting funding rates.
37693772
///
37703773
/// # Errors
37713774
///

crates/common/src/actor/tests.rs

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ use nautilus_model::{
4141
types::{Price, Quantity},
4242
};
4343
use rstest::*;
44+
use rust_decimal_macros::dec;
4445
use ustr::Ustr;
4546
#[cfg(feature = "defi")]
4647
use {
@@ -63,8 +64,8 @@ use crate::{
6364
component::Component,
6465
logging::{logger::LogGuard, logging_is_initialized},
6566
messages::data::{
66-
BarsResponse, BookResponse, CustomDataResponse, DataResponse, InstrumentResponse,
67-
InstrumentsResponse, QuotesResponse, TradesResponse,
67+
BarsResponse, BookResponse, CustomDataResponse, DataResponse, FundingRatesResponse,
68+
InstrumentResponse, InstrumentsResponse, QuotesResponse, TradesResponse,
6869
},
6970
msgbus::{
7071
self, MessageBus, get_message_bus,
@@ -178,6 +179,14 @@ impl DataActor for TestDataActor {
178179
Ok(())
179180
}
180181

182+
fn on_historical_funding_rates(
183+
&mut self,
184+
funding_rates: &[FundingRateUpdate],
185+
) -> anyhow::Result<()> {
186+
self.received_funding_rates.extend(funding_rates);
187+
Ok(())
188+
}
189+
181190
fn on_historical_bars(&mut self, bars: &[Bar]) -> anyhow::Result<()> {
182191
// Push to common received vec
183192
self.received_bars.extend(bars);
@@ -899,6 +908,49 @@ fn test_request_trades(
899908
assert_eq!(actor.received_trades[0], trade);
900909
}
901910

911+
#[rstest]
912+
fn test_request_funding_rates(
913+
clock: Rc<RefCell<TestClock>>,
914+
cache: Rc<RefCell<Cache>>,
915+
trader_id: TraderId,
916+
audusd_sim: CurrencyPair,
917+
) {
918+
let actor_id = register_data_actor(clock, cache, trader_id);
919+
let mut actor = get_actor_unchecked::<TestDataActor>(&actor_id);
920+
actor.start().unwrap();
921+
922+
let request_id = actor
923+
.request_funding_rates(audusd_sim.id, None, None, None, None, None)
924+
.unwrap();
925+
926+
let client_id = ClientId::new("TestClient");
927+
let funding_rate = FundingRateUpdate::new(
928+
audusd_sim.id,
929+
dec!(0.0001),
930+
None,
931+
UnixNanos::default(),
932+
UnixNanos::default(),
933+
);
934+
let data = vec![funding_rate];
935+
let ts_init = UnixNanos::default();
936+
let response = FundingRatesResponse::new(
937+
request_id,
938+
client_id,
939+
audusd_sim.id,
940+
data,
941+
Some(UnixNanos::from(1_695_000_000_000_000_000)),
942+
Some(UnixNanos::from(1_699_000_000_000_000_000)),
943+
ts_init,
944+
None,
945+
);
946+
947+
let data_response = DataResponse::FundingRates(response);
948+
msgbus::send_response(&request_id, data_response);
949+
950+
assert_eq!(actor.received_funding_rates.len(), 1);
951+
assert_eq!(actor.received_funding_rates[0], funding_rate);
952+
}
953+
902954
#[rstest]
903955
fn test_request_bars(
904956
clock: Rc<RefCell<TestClock>>,

crates/data/tests/client.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ use nautilus_common::{
3030
RequestBookSnapshot,
3131
RequestCommand,
3232
RequestCustomData,
33+
RequestFundingRates,
3334
RequestInstrument,
3435
RequestInstruments,
3536
RequestQuotes,
@@ -1654,6 +1655,44 @@ fn test_request_trades(
16541655
assert_eq!(rec[0], DataCommand::Request(RequestCommand::Trades(req)));
16551656
}
16561657

1658+
#[rstest]
1659+
fn test_request_funding_rates(
1660+
clock: Rc<RefCell<TestClock>>,
1661+
cache: Rc<RefCell<Cache>>,
1662+
client_id: ClientId,
1663+
venue: Venue,
1664+
) {
1665+
let recorder = Rc::new(RefCell::new(Vec::<DataCommand>::new()));
1666+
let client = Box::new(MockDataClient::new_with_recorder(
1667+
clock,
1668+
cache,
1669+
client_id,
1670+
Some(venue),
1671+
Some(recorder.clone()),
1672+
));
1673+
let adapter = DataClientAdapter::new(client_id, Some(venue), false, false, client);
1674+
1675+
let inst_id = audusd_sim().id;
1676+
let req = RequestFundingRates::new(
1677+
inst_id,
1678+
None,
1679+
None,
1680+
None,
1681+
Some(client_id),
1682+
UUID4::new(),
1683+
UnixNanos::default(),
1684+
None,
1685+
);
1686+
adapter.request_funding_rates(req.clone()).unwrap();
1687+
1688+
let rec = recorder.borrow();
1689+
assert_eq!(rec.len(), 1);
1690+
assert_eq!(
1691+
rec[0],
1692+
DataCommand::Request(RequestCommand::FundingRates(req))
1693+
);
1694+
}
1695+
16571696
#[rstest]
16581697
fn test_request_bars(
16591698
clock: Rc<RefCell<TestClock>>,

crates/data/tests/common/mocks.rs

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,15 +36,15 @@ use nautilus_common::{
3636
clock::Clock,
3737
messages::data::{
3838
DataCommand, RequestBars, RequestBookDepth, RequestBookSnapshot, RequestCommand,
39-
RequestCustomData, RequestInstrument, RequestInstruments, RequestQuotes, RequestTrades,
40-
SubscribeBars, SubscribeBookDeltas, SubscribeBookDepth10, SubscribeCommand,
41-
SubscribeCustomData, SubscribeFundingRates, SubscribeIndexPrices, SubscribeInstrument,
42-
SubscribeInstrumentClose, SubscribeInstrumentStatus, SubscribeInstruments,
43-
SubscribeMarkPrices, SubscribeQuotes, SubscribeTrades, UnsubscribeBars,
44-
UnsubscribeBookDeltas, UnsubscribeBookDepth10, UnsubscribeCommand, UnsubscribeCustomData,
45-
UnsubscribeFundingRates, UnsubscribeIndexPrices, UnsubscribeInstrument,
46-
UnsubscribeInstrumentClose, UnsubscribeInstrumentStatus, UnsubscribeInstruments,
47-
UnsubscribeMarkPrices, UnsubscribeQuotes, UnsubscribeTrades,
39+
RequestCustomData, RequestFundingRates, RequestInstrument, RequestInstruments,
40+
RequestQuotes, RequestTrades, SubscribeBars, SubscribeBookDeltas, SubscribeBookDepth10,
41+
SubscribeCommand, SubscribeCustomData, SubscribeFundingRates, SubscribeIndexPrices,
42+
SubscribeInstrument, SubscribeInstrumentClose, SubscribeInstrumentStatus,
43+
SubscribeInstruments, SubscribeMarkPrices, SubscribeQuotes, SubscribeTrades,
44+
UnsubscribeBars, UnsubscribeBookDeltas, UnsubscribeBookDepth10, UnsubscribeCommand,
45+
UnsubscribeCustomData, UnsubscribeFundingRates, UnsubscribeIndexPrices,
46+
UnsubscribeInstrument, UnsubscribeInstrumentClose, UnsubscribeInstrumentStatus,
47+
UnsubscribeInstruments, UnsubscribeMarkPrices, UnsubscribeQuotes, UnsubscribeTrades,
4848
},
4949
};
5050
use nautilus_model::identifiers::{ClientId, Venue};
@@ -594,6 +594,14 @@ impl DataClient for MockDataClient {
594594
Ok(())
595595
}
596596

597+
fn request_funding_rates(&self, request: RequestFundingRates) -> anyhow::Result<()> {
598+
if let Some(rec) = &self.recorder {
599+
rec.borrow_mut()
600+
.push(DataCommand::Request(RequestCommand::FundingRates(request)));
601+
}
602+
Ok(())
603+
}
604+
597605
fn request_bars(&self, request: RequestBars) -> anyhow::Result<()> {
598606
if let Some(rec) = &self.recorder {
599607
rec.borrow_mut()

crates/data/tests/engine.rs

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,12 @@ use nautilus_common::{
3737
clock::{Clock, TestClock},
3838
messages::data::{
3939
DataCommand, RequestBars, RequestBookDepth, RequestBookSnapshot, RequestCommand,
40-
RequestCustomData, RequestInstrument, RequestInstruments, RequestQuotes, RequestTrades,
41-
SubscribeBars, SubscribeBookDeltas, SubscribeBookDepth10, SubscribeBookSnapshots,
42-
SubscribeCommand, SubscribeCustomData, SubscribeFundingRates, SubscribeIndexPrices,
43-
SubscribeInstrument, SubscribeMarkPrices, SubscribeQuotes, SubscribeTrades,
44-
UnsubscribeBars, UnsubscribeBookDeltas, UnsubscribeBookDepth10, UnsubscribeCommand,
45-
UnsubscribeCustomData, UnsubscribeFundingRates, UnsubscribeIndexPrices,
40+
RequestCustomData, RequestFundingRates, RequestInstrument, RequestInstruments,
41+
RequestQuotes, RequestTrades, SubscribeBars, SubscribeBookDeltas, SubscribeBookDepth10,
42+
SubscribeBookSnapshots, SubscribeCommand, SubscribeCustomData, SubscribeFundingRates,
43+
SubscribeIndexPrices, SubscribeInstrument, SubscribeMarkPrices, SubscribeQuotes,
44+
SubscribeTrades, UnsubscribeBars, UnsubscribeBookDeltas, UnsubscribeBookDepth10,
45+
UnsubscribeCommand, UnsubscribeCustomData, UnsubscribeFundingRates, UnsubscribeIndexPrices,
4646
UnsubscribeInstrument, UnsubscribeMarkPrices, UnsubscribeQuotes, UnsubscribeTrades,
4747
},
4848
msgbus::{
@@ -1236,6 +1236,43 @@ fn test_execute_request_trades(
12361236
assert_eq!(recorder.borrow()[0], cmd);
12371237
}
12381238

1239+
#[rstest]
1240+
fn test_execute_request_funding_rates(
1241+
clock: Rc<RefCell<TestClock>>,
1242+
cache: Rc<RefCell<Cache>>,
1243+
data_engine: Rc<RefCell<DataEngine>>,
1244+
audusd_sim: CurrencyPair,
1245+
client_id: ClientId,
1246+
venue: Venue,
1247+
) {
1248+
let mut data_engine = data_engine.borrow_mut();
1249+
let recorder: Rc<RefCell<Vec<DataCommand>>> = Rc::new(RefCell::new(Vec::new()));
1250+
register_mock_client(
1251+
clock,
1252+
cache,
1253+
client_id,
1254+
venue,
1255+
None,
1256+
&recorder,
1257+
&mut data_engine,
1258+
);
1259+
1260+
let req = RequestFundingRates::new(
1261+
audusd_sim.id,
1262+
None, // start
1263+
None, // end
1264+
None, // limit
1265+
Some(client_id),
1266+
UUID4::new(),
1267+
UnixNanos::default(),
1268+
None, // params
1269+
);
1270+
let cmd = DataCommand::Request(RequestCommand::FundingRates(req));
1271+
data_engine.execute(cmd.clone());
1272+
1273+
assert_eq!(recorder.borrow()[0], cmd);
1274+
}
1275+
12391276
#[rstest]
12401277
fn test_execute_request_bars(
12411278
clock: Rc<RefCell<TestClock>>,

crates/infrastructure/src/sql/cache.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -743,15 +743,15 @@ impl CacheDatabaseAdapter for PostgresCacheDatabase {
743743
Ok(rx.recv()?)
744744
}
745745

746-
fn add_funding_rate(&self, funding_rate: &FundingRateUpdate) -> anyhow::Result<()> {
747-
todo!()
746+
fn add_funding_rate(&self, _funding_rate: &FundingRateUpdate) -> anyhow::Result<()> {
747+
anyhow::bail!("add_funding_rate not implemented for PostgreSQL cache adapter")
748748
}
749749

750750
fn load_funding_rates(
751751
&self,
752-
instrument_id: &InstrumentId,
752+
_instrument_id: &InstrumentId,
753753
) -> anyhow::Result<Vec<FundingRateUpdate>> {
754-
todo!()
754+
anyhow::bail!("load_funding_rates not implemented for PostgreSQL cache adapter")
755755
}
756756

757757
fn add_bar(&self, bar: &Bar) -> anyhow::Result<()> {

nautilus_trader/common/actor.pyx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3522,7 +3522,7 @@ cdef class Actor(Component):
35223522
Parameters
35233523
----------
35243524
instrument_id : InstrumentId
3525-
The tick instrument ID for the request.
3525+
The instrument ID for the request.
35263526
start : datetime
35273527
The start datetime (UTC) of request time range.
35283528
Should be left-inclusive (start <= value), but inclusiveness is not currently guaranteed.
@@ -3531,7 +3531,7 @@ cdef class Actor(Component):
35313531
If `None` then will be replaced with the current UTC time.
35323532
Should be right-inclusive (value <= end), but inclusiveness is not currently guaranteed.
35333533
limit : int, optional
3534-
The limit on the amount of trade ticks received.
3534+
The limit on the amount of funding rates received.
35353535
client_id : ClientId, optional
35363536
The specific client ID for the command.
35373537
If ``None`` then will be inferred from the venue in the instrument ID.

nautilus_trader/test_kit/mocks/data.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
from nautilus_trader.common.component import MessageBus
2323
from nautilus_trader.data.client import MarketDataClient
2424
from nautilus_trader.data.messages import RequestBars
25+
from nautilus_trader.data.messages import RequestFundingRates
2526
from nautilus_trader.data.messages import RequestInstrument
2627
from nautilus_trader.data.messages import RequestInstruments
2728
from nautilus_trader.data.messages import RequestOrderBookDepth
@@ -31,6 +32,7 @@
3132
from nautilus_trader.data.messages import SubscribeQuoteTicks
3233
from nautilus_trader.data.messages import SubscribeTradeTicks
3334
from nautilus_trader.model.data import Bar
35+
from nautilus_trader.model.data import FundingRateUpdate
3436
from nautilus_trader.model.data import OrderBookDepth10
3537
from nautilus_trader.model.data import QuoteTick
3638
from nautilus_trader.model.data import TradeTick
@@ -83,6 +85,7 @@ def __init__(
8385
self.instruments: list[Instrument] = []
8486
self.quote_ticks: list[QuoteTick] = []
8587
self.trade_ticks: list[TradeTick] = []
88+
self.funding_rates: list[FundingRateUpdate] = []
8689
self.bars: list[Bar] = []
8790
self.order_book_depths: list[OrderBookDepth10] = []
8891

@@ -125,6 +128,16 @@ def request_trade_ticks(self, request: RequestTradeTicks) -> None:
125128
request.params,
126129
)
127130

131+
def request_funding_rates(self, request: RequestFundingRates) -> None:
132+
self._handle_funding_rates_py(
133+
request.instrument_id,
134+
self.funding_rates,
135+
request.id,
136+
request.start,
137+
request.end,
138+
request.params,
139+
)
140+
128141
def request_bars(self, request: RequestBars) -> None:
129142
self._handle_bars_py(
130143
request.bar_type,

0 commit comments

Comments
 (0)