use ek_core::plugin::Plugin;
use ek_ctp::plugin::{CtpConfig, CtpPlugin};
use ek_dm::plugin::{DmConfig, DmPlugin};
use ek_oms::plugin::OmsPlugin;
pub type Builder = std::sync::Arc<dyn Fn() -> std::sync::Arc<dyn Plugin> + Send + Sync>;
pub type NamedBuilder = std::sync::Arc<dyn Fn(&str) -> std::sync::Arc<dyn Plugin> + Send + Sync>;
#[derive(Clone)]
pub struct PlugKind {
pub name: &'static str,
pub doc: &'static str,
pub build: Builder,
pub build_named: Option<NamedBuilder>,
pub name_validator: Option<NamedValidator>,
}
pub type NamedValidator = std::sync::Arc<dyn Fn(&str) -> Result<(), String> + Send + Sync>;
#[must_use]
pub fn oms_gate_builder() -> ek_oms::GateRebuild {
std::sync::Arc::new(|s: &ek_oms::RiskSpec| {
ek_risk::standard_gates(&ek_risk::RiskLimits {
max_volume_per_order: s.max_volume_per_order,
max_position_per_symbol: s.max_position_per_symbol,
price_band: s.price_band,
require_contract: s.require_contract,
max_notional: s.max_notional,
})
})
}
#[must_use]
pub fn default_kinds() -> Vec<PlugKind> {
vec![
PlugKind {
name: ek_cfg::NAME,
doc: "配置托底(save/list/delete;ek-cfg,零状态收件形貌)",
build: std::sync::Arc::new(|| std::sync::Arc::new(ek_cfg::CfgPlugin::eco_or_local())),
build_named: None, name_validator: None,
},
PlugKind {
name: ek_dm::NAME,
doc: "数据管理器(KlineManager;eTick.→eBar. 单源批)",
build: std::sync::Arc::new(|| {
std::sync::Arc::new(DmPlugin::new(DmConfig::minute(ek_dm::NAME)))
}),
build_named: None,
name_validator: None,
},
PlugKind {
name: ek_oms::NAME,
doc: "OMS 中枢(入账 + 查询 + 五段管线;地板三件 + ek-risk 四闸装配:合约预检 / 单笔手数 / 品种持仓限 / 价带)",
build: std::sync::Arc::new(|| {
std::sync::Arc::new(
OmsPlugin::builder()
.risk_spec(ek_oms::RiskSpec::default())
.gate_rebuild(oms_gate_builder())
.risk_gates(ek_risk::standard_gates(&ek_risk::RiskLimits::default()))
.build(),
)
}),
build_named: None,
name_validator: None,
},
PlugKind {
name: "ctp", doc: "CTP 网关(native 关 = 纯逻辑驱动;账号经 {gw}.configure 手工注入,插件不读配置文件)",
build: std::sync::Arc::new(|| build_ctp("")),
build_named: Some(std::sync::Arc::new(build_ctp)),
name_validator: Some(std::sync::Arc::new(|name| {
if ek_ctp::plugin::is_derived_gateway_name(name) {
Ok(())
} else {
Err(format!(
"ctp 命名实例须为派生名 ctp_<broker>_<账号>(仅小写字母数字,≤32);收到 {name:?}"
))
}
})),
},
]
}
fn build_ctp(name: &str) -> std::sync::Arc<dyn Plugin> {
let cfg = CtpConfig {
gateway_name: name.to_string(),
..CtpConfig::default()
};
#[cfg(feature = "ctp-native")]
{
CtpPlugin::with_native(cfg, "target/ctp-flow")
}
#[cfg(not(feature = "ctp-native"))]
{
std::sync::Arc::new(CtpPlugin::new(cfg))
}
}
pub struct DynPlugin {
inner: std::sync::Arc<dyn Plugin>,
}
impl DynPlugin {
pub fn wrap(inner: std::sync::Arc<dyn Plugin>) -> std::sync::Arc<Self> {
std::sync::Arc::new(Self { inner })
}
}
impl Plugin for DynPlugin {
fn name(&self) -> &str {
self.inner.name()
}
fn deps(&self) -> &[&str] {
self.inner.deps()
}
fn routes(&self) -> Vec<std::borrow::Cow<'static, str>> {
self.inner.routes()
}
fn mailbox_soft_cap(&self) -> u64 {
self.inner.mailbox_soft_cap()
}
fn version(&self) -> std::borrow::Cow<'static, str> {
self.inner.version()
}
fn services(&self) -> Vec<ek_core::service::ServiceDesc> {
self.inner.services()
}
fn on_init(&self, ctx: &ek_core::context::PluginContext) {
self.inner.on_init(ctx);
}
fn on_start(&self) {
self.inner.on_start();
}
fn on_stop(&self) {
self.inner.on_stop();
}
fn on_mail(&self, event: &ek_event::Event) {
self.inner.on_mail(event);
}
fn as_configurable(&self) -> Option<&dyn ek_core::section::Configurable> {
self.inner.as_configurable()
}
}