Skip to content

Commit 15b910f

Browse files
committed
feat(quant): Phase 2 Elite Quant Architecture & Reliability patterns
1 parent 6bdce06 commit 15b910f

38 files changed

Lines changed: 662 additions & 110 deletions

.env.example

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Core Configuration
2+
SOL_RPC=https://api.mainnet-beta.solana.com
3+
SOL_WS=wss://api.mainnet-beta.solana.com
4+
5+
# Authentication
6+
# Your private key (Keep secure, do not commit!)
7+
SOL_PRIVATE_KEY=your_private_key_here
8+
9+
# API Integrations
10+
ANTHROPIC_API_KEY=your_anthropic_api_key
11+
FINNHUB_API_KEY=your_finnhub_api_key
12+
ALPACA_API_KEY=your_alpaca_key
13+
ALPACA_SECRET_KEY=your_alpaca_secret
14+
ALPACA_BASE_URL=https://paper-api.alpaca.markets
15+
16+
# Feature Flags
17+
USE_MOCK=1 # Remove this to run against real exchanges

Cargo.toml

Lines changed: 31 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,31 @@
1-
[workspace]
2-
resolver = "2"
3-
members = [
4-
"crates/common",
5-
"crates/ingestion",
6-
"crates/parser",
7-
"crates/feature",
8-
"crates/strategy",
9-
"crates/model",
10-
"crates/risk",
11-
"crates/executor",
12-
"crates/signer",
13-
"crates/relay",
14-
"crates/daemon",
15-
"crates/event_bus",
16-
"crates/cli",
17-
"crates/tui",
18-
"crates/web",
19-
"crates/tests",
20-
"crates/persistence",
21-
"crates/web-dashboard",
22-
"crates/ai",
23-
"crates/dashboard"
24-
]
25-
26-
[profile.release]
27-
opt-level = 3
28-
lto = true
29-
codegen-units = 1
30-
panic = "abort"
31-
strip = true
1+
[workspace]
2+
resolver = "2"
3+
members = [
4+
"crates/common",
5+
"crates/ingestion",
6+
"crates/parser",
7+
"crates/feature",
8+
"crates/strategy",
9+
"crates/model",
10+
"crates/risk",
11+
"crates/executor",
12+
"crates/signer",
13+
"crates/relay",
14+
"crates/daemon",
15+
"crates/event_bus",
16+
"crates/cli",
17+
"crates/tui",
18+
"crates/web",
19+
"crates/tests",
20+
"crates/persistence",
21+
"crates/web-dashboard",
22+
"crates/ai",
23+
"crates/dashboard"
24+
, "crates/ml"]
25+
26+
[profile.release]
27+
opt-level = 3
28+
lto = true
29+
codegen-units = 1
30+
panic = "abort"
31+
strip = true

clippy.toml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
avoid-breaking-exported-api = false
2+
cognitive-complexity-threshold = 30
3+
too-many-arguments-threshold = 10
4+
type-complexity-threshold = 250
5+
enum-variant-name-threshold = 5
6+
7+
# Allow standard doc omissions for internal project until phase 5
8+
allow-missing-docs = true

config/prompts/dexter_system.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
You are Dexter, an elite quantitative analyst.
2+
Analyze the following market conditions and news, and determine a directional edge for the specified asset.
3+
Output must be concise, highlighting key valuation multiples, revenue impact, and an ultimate rating of BUY, RISK, or NEUTRAL.
4+
Provide specific reasoning using numerical estimates.

config/prompts/mirofish_system.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
You are MiroFish, an institutional swarm intelligence simulator.
2+
Given the current order book depth and macro sentiment, output a probability distribution across three scenarios:
3+
1. Rally
4+
2. Sideways
5+
3. Dip
6+
7+
Include institutional accumulation metrics and retail sentiment scores.
8+
Format your output cleanly for a terminal UI.

crates/ai/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,5 @@ tracing = "0.1"
1313
anyhow = "1.0"
1414
chumsky = "0.9" # Optional depending on parsing needs
1515
event_bus = { path = "../event_bus" }
16+
schemars = "1.2.1"
17+
jsonschema = "0.17"

crates/ai/src/client/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
pub mod validator;
2+
pub mod rate_limiter;
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
use std::time::{Instant, Duration};
2+
use tokio::sync::Mutex;
3+
use anyhow::{Result, bail};
4+
use std::sync::Arc;
5+
6+
pub struct TokenBucketLimiter {
7+
capacity: usize,
8+
tokens: Mutex<usize>,
9+
refill_rate_per_sec: f64,
10+
last_refill: Mutex<Instant>,
11+
}
12+
13+
impl TokenBucketLimiter {
14+
pub fn new(capacity: usize, refill_rate_per_sec: f64) -> Arc<Self> {
15+
Arc::new(Self {
16+
capacity,
17+
tokens: Mutex::new(capacity),
18+
refill_rate_per_sec,
19+
last_refill: Mutex::new(Instant::now()),
20+
})
21+
}
22+
23+
pub async fn acquire(&self, amount: usize) -> Result<()> {
24+
let mut tokens_guard = self.tokens.lock().await;
25+
let mut time_guard = self.last_refill.lock().await;
26+
27+
// Calculate refill based on elapsed time elapsed * rate
28+
let now = Instant::now();
29+
let elapsed_secs = now.duration_since(*time_guard).as_secs_f64();
30+
let add_tokens = (elapsed_secs * self.refill_rate_per_sec) as usize;
31+
32+
if add_tokens > 0 {
33+
*tokens_guard = std::cmp::min(self.capacity, *tokens_guard + add_tokens);
34+
// Only bump the clock forward by the *full fractional tokens* we actually credited,
35+
// but for a trading bot approximation, snapping to now is fine.
36+
*time_guard = now;
37+
}
38+
39+
if *tokens_guard >= amount {
40+
*tokens_guard -= amount;
41+
Ok(())
42+
} else {
43+
// Need to wait. Real implementation might sleep or just reject immediately.
44+
tracing::warn!("Rate limit exceeded. Required: {}, Available: {}", amount, *tokens_guard);
45+
bail!("Anthropic API rate limit exceeded");
46+
}
47+
}
48+
}

crates/ai/src/client/validator.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
use schemars::{schema_for, JsonSchema};
2+
use serde::{Deserialize, Serialize};
3+
use anyhow::{Result, bail};
4+
use jsonschema::JSONSchema;
5+
6+
#[derive(Serialize, Deserialize, JsonSchema, Debug)]
7+
pub struct DexterResponse {
8+
pub revenue_impact: String,
9+
pub primary_catalyst: String,
10+
#[validate(range(min = -1.0, max = 1.0))]
11+
pub sentiment_score: f64,
12+
pub recommended_action: String, // BUY, SELL, HOLD
13+
}
14+
15+
pub struct SchemaValidator {
16+
compiled_schema: JSONSchema,
17+
}
18+
19+
impl SchemaValidator {
20+
pub fn new() -> Result<Self> {
21+
let schema = schema_for!(DexterResponse);
22+
let schema_value = serde_json::to_value(&schema)?;
23+
let compiled = JSONSchema::compile(&schema_value).map_err(|e| anyhow::anyhow!("Schema compilation failed: {}", e))?;
24+
Ok(Self {
25+
compiled_schema: compiled,
26+
})
27+
}
28+
29+
pub fn validate_and_parse(&self, llm_json_str: &str) -> Result<DexterResponse> {
30+
let value: serde_json::Value = serde_json::from_str(llm_json_str)?;
31+
32+
if let Err(errors) = self.compiled_schema.validate(&value) {
33+
let error_msgs: Vec<String> = errors.map(|e| e.to_string()).collect();
34+
tracing::error!("Claude returned invalid JSON schema: {:?}", error_msgs);
35+
bail!("Schema validation failed: {:?}", error_msgs);
36+
}
37+
38+
let response: DexterResponse = serde_json::from_value(value)?;
39+
Ok(response)
40+
}
41+
}

crates/ai/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
pub mod anthropic_client;
22
pub mod analyst;
33
pub mod simulator;
4+
pub mod client;

0 commit comments

Comments
 (0)