1 个不稳定版本

0.1.1 2024 年 3 月 29 日

72金融

MIT 许可证

210KB
3.5K SLoC

XTB-Client

XTB-Client 库提供了对 XTB 证券商 API 的类型化和简单易用的连接器实现。

  • 编程风格: 异步
  • 框架: tokio
  • XTB API 版本: 2.5
  • 请求/响应 API: 支持
  • 流 API: 支持

警告

此库仍在开发中。库 API 可能会更改,代码中可能存在一些错误。

如何使用

XTB 接口由实现 XtbApiXtbStreamApi 特性的 XtbClient 结构体提供。可以通过 XtbClientBuilder 结构体创建该结构体,并在创建时自动连接到服务器并执行 login 命令。如果两者都成功,则返回 XtbClient 实例。

配置

XtbClientXtbClientBuilder 配置。构建器有三个初始化方法

  • new(api_url: &str, stream_api_url: &str) - 创建具有自定义 URL 的新实例。
  • new_real() - 创建具有预设真实账户服务器的实例。
  • new_demo() - 创建具有预设演示账户服务器的实例。
  • new_bare() - 创建没有设置任何值的实例。

可以使用前缀为 with_ 的设置器(选项平铺到底层类型)和未前缀的获取器来覆盖以下属性

  • api_url: Option<String> - 请求/响应 API 服务器的 URL。
  • stream_api_url: Option<String> - 流 API 服务器的 URL。
  • app_id: Option<String> - 可选的应用程序 ID(官方文档中已标记为过时)。
  • app_name: Option<String> - 可选的应用程序名称(官方文档中已标记为过时)。
  • ping_period: Option<u64> - ping 请求之间的时间间隔(默认为 30 秒)

当配置了构建器实例时,可以调用 build 方法。该方法接受两个 &str 参数:用户名和密码。

当调用该方法时,会创建服务器连接,用户登录,并启动 ping tokio 绿色线程。

use xtb_client::XtbClientBuilder;


#[tokio::main]
fn main() {
  let real_builder = XtbClientBuilder::new_real();
  let demo_builder = XtbClientBuilder::new_demo();
  let custom_builder = XtbClientBuilder::new("wss://my-server.com/api", "wss://my-server.com/apiStream").with_ping_period(20u64);
  let bare_builder = XtbClientBuilder::new_bare().with_api_url("wss://my-server.com/api").with_stream_api_url("wss://my-server.com/apiStream");
  
  let client = custom_builder.build("12345", "reallySecretPassword");
}

请求/响应 API

与服务器通信的最简单方法是请求/响应 API。此 API 总是对请求返回一个响应。

方法名称与命令名称转换为 snake_case 相对应。示例

  • getAllSymbols -> get_all_symbols
  • getCalendar -> get_calendar
  • getVersion -> get_version

一些命令在特质的公共接口中没有实现

  • login - 由 XtbClient 创建过程自动执行
  • logout - 当 XtbClient 实例被丢弃时自动执行
  • ping - 由 XtbClient 实例每 30 秒定期执行(可以配置)

流 API

流 API 通过 DataStream 结构传递的消息流向消费者提供数据。当 DataStream 实例被丢弃时,订阅会自动取消。

流 API 实现使用内部订阅计数器,因此如果有两个订阅者订阅了相同的信息(例如 USDEUR 的 tick 价格),第一个订阅者的取消订阅不会切断第二个订阅者与信息的连接。

方法名称与命令名称转换为 snake_case 相对应,并使用 subscribe_ 前缀代替 get_ 前缀。示例

  • getCandles -> subscribe_candles
  • getTrades -> subscribe_trades
  • getProfits -> subscribe_profits

一些命令在特质的公共接口中没有实现

  • ping - 由 XtbClient 实例每 30 秒定期执行(可以配置)

低级接口

库还公开了低级连接。

请求/响应连接

XtbConnection 特质及其实现者 BasicXtbConnection 为请求-响应命令提供了对 XTB 服务器的低级连接。

该特性提供了send_command方法。此方法接受命令名称(例如getNews)和用作命令参数的有效负载。如果没有参数,则传递None

调用方法后,将返回ResponsePromise结构体实例。它是可等待的,可以返回来自服务器的响应。如果命令成功,结果为Ok(Response);如果命令失败,则结果为Err(ErrorResponse)

流连接

XtbStreamConnection特性和其实现者BasicStreamConnection提供了对XTB流服务器的低级连接,用于数据流。

该特性提供了subscribeunsubscribemake_message_stream方法。

subscribe方法接受命令名称和可选参数作为参数。参数必须是NoneSome(serde_json::Value::Null),用于无参数的命令,以及Some(serde_json::Value::Object),用于带参数的命令。当命令发送成功时,服务器应流式传输请求的数据。

unsubscribe方法与subscribe类似,但其效果是停止数据流。

make_message_stream为从XTB服务器传递的消息创建本地订阅。它接受DataMessageFilter枚举作为参数,并使用它通过给定的谓词过滤传入的消息。可用的过滤器如下

  • Always(默认)- 将所有消息传递给消费者
  • Never - 不传递任何消息给消费者
  • Command(String) - 根据从服务器接收到的数据消息的command字段过滤消息
  • FieldValue { name: String, value: serde_json::Value } - 根据从服务器接收到的数据消息的data字段的字段名过滤消息。如果data包含类型为serde_json::Value::Object的对象,并且该对象具有名为name的键,且该字段包含与value相同的值,则过滤器匹配。
  • Custom(Box<dyn Fn(&StreamDataMessage) -> bool + Send + Sync>) - 自定义过滤器函数
  • All(Vec<DataMessageFilter>) - 用于存储零个、一个或多个谓词的容器。当且仅当所有谓词匹配时匹配。如果谓词列表为空,则返回 true
  • Any(Vec<DataMessageFilter>) - 用于存储零个、一个或多个谓词的容器。如果任何谓词匹配则匹配。如果谓词列表为空,则返回 false

注意:尚未实现 Not,但可以使用 Custom 变体来创建它。

make_message_stream 返回 MessageStream 特质的实现。此特质提供了返回匹配过滤器的传入消息的 next() 方法。

示例

示例 1

简单 API 调用来获取所有可用的符号。

use tracing::Level;
use xtb_client::RequestResponseApi;
use xtb_client::schema::GetAllSymbolsRequest;

#[tokio::main]
async fn main() {
    dotenvy::dotenv().unwrap_or_default();
    let subscriber = tracing_subscriber::fmt().with_max_level(Level::DEBUG).finish();
    tracing::subscriber::set_global_default(subscriber).unwrap();

    let username = dotenvy::var("XTB_USERNAME").unwrap();
    let password = dotenvy::var("XTB_PASSWORD").unwrap();
    let api_server = dotenvy::var("XTB_API_SERVER").unwrap();
    let stream_server = dotenvy::var("XTB_STREAM_SERVER").unwrap();

    let mut client = xtb_client::XtbClientBuilder::new(&api_server, &stream_server).build(&username, &password).await.unwrap();

    let symbols = client.get_all_symbols(GetAllSymbolsRequest::default()).await.unwrap();
    println!("{}", serde_json::to_string_pretty(&symbols).unwrap())
}

示例 2

订阅 keppAlive 消息。

use tracing::Level;
use xtb_client::{StreamApi};
use xtb_client::schema::{StreamGetKeepAliveSubscribe};

#[tokio::main]
async fn main() {
    dotenvy::dotenv().unwrap_or_default();
    let subscriber = tracing_subscriber::fmt().with_max_level(Level::DEBUG).finish();
    tracing::subscriber::set_global_default(subscriber).unwrap();

    let username = dotenvy::var("XTB_USERNAME").unwrap();
    let password = dotenvy::var("XTB_PASSWORD").unwrap();
    let api_server = dotenvy::var("XTB_API_SERVER").unwrap();
    let stream_server = dotenvy::var("XTB_STREAM_SERVER").unwrap();

    let mut client = xtb_client::XtbClientBuilder::new(&api_server, &stream_server).build(&username, &password).await.unwrap();

    let mut listener = client.subscribe_keep_alive(StreamGetKeepAliveSubscribe::default()).await.unwrap();

    while let Some(item) = listener.next().await.unwrap() {
        println!("Keep alive received: {}", item.timestamp);
    }

    println!("Stream closed");
}

TODO

该库处于开发状态(版本号以 0 开头),直到以下步骤完成。

  • tests - 缺少主要功能的测试
  • dummy implementations - 创建连接和客户端特质的示例实现。这些实现可用于测试或演示示例。
  • 未知的枚举变体 - 值为 104MarginMode 变体和值为 5 和 6 的 QuoteId 变体在官方文档中没有提及。在库稳定之前必须知道这些变体的含义。

请买我一杯 咖啡 啤酒

如果您喜欢这个库,或者您想支持其开发,请通过一杯冰冷的 啤酒 支持我。啤酒味道很好,富含维生素 :-)

依赖项

~7–17MB
~235K SLoC