FX-Store provides both HTTP REST API and native Rust client library for querying and managing financial time-series data.
http://localhost:9000/api/v1
Currently uses API key authentication:
curl -H "Authorization: Bearer YOUR_API_KEY" \
http://localhost:9000/api/v1/queryGET /healthResponse:
{
"status": "ok",
"uptime": 3600,
"version": "1.0.0"
}GET /query?symbol={symbol}&start={start}&end={end}Parameters:
symbol(required): Trading symbol (e.g., "EURUSD")start(required): Start timestamp (ISO 8601)end(required): End timestamp (ISO 8601)format(optional): Response format ("json", "csv", "parquet")limit(optional): Maximum records to return
Example:
curl "http://localhost:9000/api/v1/query?symbol=EURUSD&start=2023-01-01T00:00:00Z&end=2023-01-02T00:00:00Z"Response:
{
"symbol": "EURUSD",
"records": [
{
"timestamp": "2023-01-01T00:00:00Z",
"open": 1.05432,
"high": 1.05478,
"low": 1.05401,
"close": 1.05456,
"volume": 12500
}
],
"count": 1440,
"query_ms": 15
}POST /import
Content-Type: multipart/form-dataParameters:
file: CSV file to importsymbol: Trading symbolcompression_level: Compression level (1-22)
GET /metricsReturns Prometheus-format metrics for monitoring.
[dependencies]
fx-store = "1.0"
tokio = { version = "1.0", features = ["full"] }use fx_store::{Client, TimeRange};
use chrono::{Utc, Duration};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = Client::connect("localhost:9000").await?;
let records = client
.query("EURUSD")
.range(Utc::now() - Duration::days(1), Utc::now())
.execute()
.await?;
println!("Found {} records", records.len());
Ok(())
}let client = Client::connect("localhost:9000").await?;
let client = Client::with_config(config).await?;let query = client
.query("EURUSD")
.range(start, end)
.limit(1000)
.format(OutputFormat::Json);
let records = query.execute().await?;let mut stream = client.subscribe("EURUSD").await?;
while let Some(ohlcv) = stream.next().await {
println!("Real-time: {:?}", ohlcv);
}let symbols = vec!["EURUSD", "GBPUSD", "USDJPY"];
let results = client.query_batch(symbols, range).await?;#[derive(Debug, Serialize, Deserialize)]
pub struct OHLCV {
pub timestamp: DateTime<Utc>,
pub open: f64,
pub high: f64,
pub low: f64,
pub close: f64,
pub volume: u32,
}pub struct QueryOptions {
pub symbol: String,
pub start: DateTime<Utc>,
pub end: DateTime<Utc>,
pub limit: Option<usize>,
pub format: OutputFormat,
}pub enum OutputFormat {
Json,
Csv,
Parquet,
Binary,
}200: Success400: Bad Request (invalid parameters)404: Symbol not found429: Rate limit exceeded500: Internal server error
#[derive(Debug, thiserror::Error)]
pub enum FxStoreError {
#[error("Connection failed: {0}")]
Connection(String),
#[error("Query failed: {0}")]
Query(String),
#[error("Symbol not found: {0}")]
SymbolNotFound(String),
#[error("Invalid time range")]
InvalidTimeRange,
}- Query API: 100 requests/minute per API key
- Import API: 10 requests/minute per API key
- WebSocket: 1000 messages/minute per connection
import requests
from datetime import datetime, timedelta
# Query data
response = requests.get(
"http://localhost:9000/api/v1/query",
params={
"symbol": "EURUSD",
"start": (datetime.now() - timedelta(days=1)).isoformat(),
"end": datetime.now().isoformat(),
"format": "json"
}
)
data = response.json()
print(f"Found {data['count']} records")const ws = new WebSocket('ws://localhost:9000/ws');
ws.on('open', () => {
ws.send(JSON.stringify({
action: 'subscribe',
symbol: 'EURUSD'
}));
});
ws.on('message', (data) => {
const ohlcv = JSON.parse(data);
console.log('Real-time update:', ohlcv);
});See deployment.md for server configuration options.
let config = ClientConfig {
endpoint: "http://localhost:9000".to_string(),
api_key: Some("your-api-key".to_string()),
timeout: Duration::from_secs(30),
retry_attempts: 3,
};
let client = Client::with_config(config).await?;