Skip to main content

qs_backtest_api/
client.rs

1use std::pin::Pin;
2
3use async_trait::async_trait;
4use futures::Stream;
5use qs_service::TransportFailure;
6use thiserror::Error;
7
8use crate::{
9    AddProfileRequest, AddProfileResponse, BacktestEvent, BacktestStatusResponse,
10    CancelBacktestResponse, DeleteResultArtifactRequest, DeleteResultArtifactResponse,
11    GetBacktestResultResponse, GetResultArtifactChunkRequest, GetResultArtifactChunkResponse,
12    ListProfilesResponse, ListSymbolsRequest, ListSymbolsResponse, PingResponse,
13    ReloadProfilesResponse, RemoveProfileRequest, RemoveProfileResponse, RunBacktestMultiRequest,
14    RunBacktestMultiResponse, RunBacktestRequest, RunBacktestResponse, SubmitBacktestRequest,
15    SubmitBacktestResponse,
16};
17
18pub type BacktestEventStream =
19    Pin<Box<dyn Stream<Item = Result<BacktestEvent, BacktestClientError>> + Send>>;
20
21/// Provider-neutral client port for the retained backtest-job workflow.
22#[async_trait]
23pub trait BacktestClient: Send + Sync {
24    async fn ping(&self) -> Result<PingResponse, BacktestClientError>;
25    async fn submit(
26        &self,
27        request: SubmitBacktestRequest,
28    ) -> Result<SubmitBacktestResponse, BacktestClientError>;
29    async fn status(&self, job_id: &str) -> Result<BacktestStatusResponse, BacktestClientError>;
30    async fn watch(&self, job_id: &str) -> Result<BacktestEventStream, BacktestClientError>;
31    async fn result(&self, job_id: &str) -> Result<GetBacktestResultResponse, BacktestClientError>;
32    async fn get_result_artifact_chunk(
33        &self,
34        request: GetResultArtifactChunkRequest,
35    ) -> Result<GetResultArtifactChunkResponse, BacktestClientError>;
36    async fn delete_result_artifact(
37        &self,
38        request: DeleteResultArtifactRequest,
39    ) -> Result<DeleteResultArtifactResponse, BacktestClientError>;
40    async fn cancel(&self, job_id: &str) -> Result<CancelBacktestResponse, BacktestClientError>;
41}
42
43/// Provider-neutral client port for finite synchronous backtest execution.
44#[async_trait]
45pub trait BacktestSyncClient: Send + Sync {
46    async fn run_backtest(
47        &self,
48        request: RunBacktestRequest,
49    ) -> Result<RunBacktestResponse, BacktestClientError>;
50    async fn run_backtest_multi(
51        &self,
52        request: RunBacktestMultiRequest,
53    ) -> Result<RunBacktestMultiResponse, BacktestClientError>;
54}
55
56/// Provider-neutral client port for profile and market-data discovery.
57#[async_trait]
58pub trait BacktestDiscoveryClient: Send + Sync {
59    async fn list_profiles(&self) -> Result<ListProfilesResponse, BacktestClientError>;
60    async fn list_symbols(
61        &self,
62        request: ListSymbolsRequest,
63    ) -> Result<ListSymbolsResponse, BacktestClientError>;
64}
65
66/// Provider-neutral client port for runtime profile administration.
67#[async_trait]
68pub trait BacktestAdminClient: Send + Sync {
69    async fn add_profile(
70        &self,
71        request: AddProfileRequest,
72    ) -> Result<AddProfileResponse, BacktestClientError>;
73    async fn remove_profile(
74        &self,
75        request: RemoveProfileRequest,
76    ) -> Result<RemoveProfileResponse, BacktestClientError>;
77    async fn reload_profiles(&self) -> Result<ReloadProfilesResponse, BacktestClientError>;
78}
79
80#[derive(Debug, Clone, Error)]
81pub enum BacktestClientError {
82    #[error("backtest service rejected the request: {0}")]
83    Service(String),
84    #[error(transparent)]
85    Transport(#[from] TransportFailure),
86    #[error(transparent)]
87    Protocol(#[from] BacktestServiceProtocolError),
88}
89
90#[derive(Debug, Clone, Error)]
91#[error("backtest service protocol failure: {detail}")]
92pub struct BacktestServiceProtocolError {
93    pub detail: String,
94}