Enterprise quant teams face a recurring problem: generic market data tools solve generic problems. When your trading infrastructure requires domain-specific data enrichment, custom alerting logic, or proprietary risk calculations, you either bolt on fragile workarounds or build from scratch.
The TickDB SKILL protocol changes this calculus. SKILL (Structured Capability Integration for Language-model Loops) provides a standardized extension mechanism that lets enterprise teams embed TickDB's real-time market data capabilities directly into their own tooling—without forking the core product or maintaining fragile middleware.
This article dissects the SKILL protocol from the inside out. We cover development specifications, function extension patterns, authentication flows, and private deployment strategies for teams that need more than the standard TickDB API provides.
The SKILL Protocol: Architecture Overview
What SKILL Actually Is
SKILL is not a plugin system. It is a structured JSON-based protocol for defining callable capabilities that an AI agent can invoke on behalf of a user. Each SKILL is a self-contained capability bundle that declares:
- Name and version: The identifier the AI agent uses to route requests
- Function signatures: JSON Schema definitions of what the SKILL can execute
- Runtime configuration: Credentials, endpoints, and environment-specific parameters
- Execution contracts: Input/output contracts that the AI runtime validates
SKILL Definition Schema (simplified)
{
"name": "tickdb-market-data",
"version": "1.0.0",
"description": "Real-time and historical market data via TickDB",
"functions": [...],
"runtime": {
"baseUrl": "https://api.tickdb.ai",
"auth": {
"type": "api-key",
"header": "X-API-Key"
}
}
}
Why This Architecture Matters for Enterprise
The critical insight is that SKILL operates at the capability layer, not the transport layer. Your custom SKILL does not replace TickDB's API—it wraps TickDB's capabilities with your business logic.
Consider two deployment patterns:
| Pattern | Description | Enterprise fit |
|---|---|---|
| Pre-processing SKILL | Enriches raw TickDB data before delivery | Custom normalization, currency conversion, symbol mapping |
| Post-processing SKILL | Applies business logic after data retrieval | Risk calculation, alert filtering, P&L attribution |
| Composite SKILL | Chains multiple data sources with custom logic | Multi-vendor aggregation with TickDB as primary |
The flexibility to position your logic at any point in the data pipeline is what makes SKILL enterprise-appropriate. You are not constrained to the features TickDB ships; you are building on top of a capability interface.
SKILL Development Specifications
Project Structure
A production SKILL project follows a standardized layout:
tickdb-enterprise-skill/
├── skill.json # SKILL manifest (the descriptor)
├── functions/
│ ├── get_realtime_quote.js
│ ├── query_historical.js
│ └── calculate_position.js
├── config/
│ ├── development.json
│ ├── staging.json
│ └── production.json
├── tests/
│ └── integration.test.js
└── package.json
The skill.json manifest is the contract between your SKILL and the AI runtime. Every function you expose must have a complete JSON Schema definition.
Function Definition Schema
Each function in your SKILL requires three components:
- Metadata: Name, description, and version
- Parameters: JSON Schema defining required and optional inputs
- Handler: The execution logic (Node.js or Python runtime)
Here is a complete function definition for a custom position-sizing function:
// functions/calculate_position_size.js
/**
* Calculates position size based on risk parameters and current volatility.
* Used for real-time risk management in volatility-adjusted strategies.
*
* @param {object} params
* @param {number} params.account_equity - Current account equity in USD
* @param {number} params.risk_percent - Maximum risk per trade (0.01 = 1%)
* @param {number} params.stop_loss_pct - Stop loss percentage (0.02 = 2%)
* @param {string} params.symbol - Target symbol (e.g., "NVDA.US")
* @param {object} params.context - Runtime context (auth, config, logger)
*
* @returns {object} { size: number, risk_amount: number, adjusted_stop: number }
*/
const calculatePositionSize = (params, context) => {
const { account_equity, risk_percent, stop_loss_pct, symbol } = params;
// Validate inputs
if (!account_equity || account_equity <= 0) {
throw new Error("INVALID_EQUITY: account_equity must be a positive number");
}
const risk_amount = account_equity * risk_percent;
const position_value = risk_amount / stop_loss_pct;
// Fetch current price to convert to share count
const quote = context.tickdb.getQuote(symbol);
const share_count = Math.floor(position_value / quote.price);
return {
size: share_count,
risk_amount: parseFloat(risk_amount.toFixed(2)),
adjusted_stop: parseFloat((quote.price * (1 - stop_loss_pct)).toFixed(2)),
notional_value: parseFloat((share_count * quote.price).toFixed(2)),
risk_reward_ratio: (quote.price - quote.price * (1 - stop_loss_pct)) /
(quote.price * (1 + stop_loss_pct * 2) - quote.price)
};
};
module.exports = { handler: calculatePositionSize };
The Context Object: Your Bridge to TickDB
The context object is your interface to the underlying TickDB capabilities. It exposes:
| Context method | Returns | Use case |
|---|---|---|
context.tickdb.getQuote(symbol) |
Real-time quote | Pre-trade validation |
context.tickdb.getDepth(symbol, levels) |
Order book snapshot | Liquidity assessment |
context.tickdb.getKline(symbol, interval, limit) |
OHLCV candles | Historical analysis |
context.tickdb.getTrades(symbol, limit) |
Recent trades | Order flow analysis |
context.config.get(key) |
Runtime configuration | Environment-specific settings |
context.logger.info(message) |
Log entry | Auditing and debugging |
The context is injected by the SKILL runtime, so you never handle credentials directly in your function code. This separation is critical for security compliance.
Function Extension Patterns
Pattern 1: Data Enrichment
Transform raw TickDB output into domain-specific formats:
// functions/enrich_us_equity_quote.js
const enrichQuote = (params, context) => {
const { symbol } = params;
// Fetch raw quote from TickDB
const raw_quote = context.tickdb.getQuote(symbol);
// Fetch supporting data
const depth = context.tickdb.getDepth(symbol, 5);
const recent_trades = context.tickdb.getTrades(symbol, 20);
// Calculate derived metrics
const buy_volume = recent_trades
.filter(t => t.side === 'buy')
.reduce((sum, t) => sum + t.size, 0);
const sell_volume = recent_trades
.filter(t => t.side === 'sell')
.reduce((sum, t) => sum + t.size, 0);
// Order flow imbalance
const imbalance = (buy_volume - sell_volume) / (buy_volume + sell_volume);
// Depth-weighted spread
const weighted_spread = depth.reduce((sum, level, i) => {
return sum + (level.ask - level.bid) / (i + 1);
}, 0);
return {
symbol: raw_quote.symbol,
price: raw_quote.price,
bid_ask_spread: parseFloat((raw_quote.ask - raw_quote.bid).toFixed(4)),
order_flow_imbalance: parseFloat(imbalance.toFixed(4)),
depth_weighted_spread: parseFloat(weighted_spread.toFixed(4)),
volume_ratio: parseFloat((buy_volume / (sell_volume || 1)).toFixed(2)),
liquidity_score: raw_quote.volume / weighted_spread,
timestamp: raw_quote.timestamp
};
};
module.exports = { handler: enrichQuote };
This pattern is particularly useful for teams running factor models that require normalized input features.
Pattern 2: Multi-Step Workflows
Chain TickDB calls with conditional logic:
// functions/liquidity_regime_detection.js
const detectLiquidityRegime = (params, context) => {
const { symbol, lookback_minutes = 5 } = params;
// Step 1: Establish baseline
const baseline_depth = context.tickdb.getDepth(symbol, 10);
const baseline_spread = baseline_depth.reduce(
(sum, l) => sum + (l.ask - l.bid), 0
) / baseline_depth.length;
// Step 2: Monitor real-time deviation
const current_depth = context.tickdb.getDepth(symbol, 10);
const current_spread = current_depth.reduce(
(sum, l) => sum + (l.ask - l.bid), 0
) / current_depth.length;
// Step 3: Classify regime
const spread_ratio = current_spread / baseline_spread;
let regime;
let confidence;
if (spread_ratio > 3.0) {
regime = 'crisis'; // Spread exploded, likely news event
confidence = 0.92;
} else if (spread_ratio > 1.5) {
regime = 'stressed'; // Elevated but not extreme
confidence = 0.78;
} else if (spread_ratio < 0.5) {
regime = 'collapsed'; // Tight spread, low volume risk
confidence = 0.65;
} else {
regime = 'normal';
confidence = 0.95;
}
// Step 4: Fetch regime-specific recommendations
const recommendations = {
crisis: { position_sizing: 0.5, require_confirmation: true },
stressed: { position_sizing: 0.75, require_confirmation: false },
collapsed: { position_sizing: 1.0, require_confirmation: false },
normal: { position_sizing: 1.0, require_confirmation: false }
};
return {
symbol,
regime,
confidence,
spread_ratio: parseFloat(spread_ratio.toFixed(3)),
baseline_spread: parseFloat(baseline_spread.toFixed(4)),
current_spread: parseFloat(current_spread.toFixed(4)),
recommendations: recommendations[regime],
detected_at: new Date().toISOString()
};
};
module.exports = { handler: detectLiquidityRegime };
Pattern 3: Private Data Integration
Blend TickDB data with proprietary internal datasets:
// functions/alpha_signal_composite.js
const buildAlphaComposite = (params, context) => {
const { symbols, weights = {} } = params;
// Default weights if not provided
const default_weights = { momentum: 0.3, flow: 0.4, sentiment: 0.3 };
const final_weights = { ...default_weights, ...weights };
const signals = symbols.map(symbol => {
// Fetch market data from TickDB
const quote = context.tickdb.getQuote(symbol);
const kline = context.tickdb.getKline(symbol, '1h', 24);
// Fetch proprietary signals (from your internal database)
const internal_signals = context.internal.getSignals(symbol);
// Calculate momentum signal from price series
const returns = kline.slice(-12).map(
(k, i, arr) => i > 0 ? (k.close - arr[i-1].close) / arr[i-1].close : 0
);
const momentum = returns.reduce((sum, r) => sum + r, 0) / returns.length;
// Calculate flow signal from order imbalance
const recent_trades = context.tickdb.getTrades(symbol, 50);
const flow_signal = recent_trades
.filter(t => t.side === 'buy')
.reduce((s, t) => s + t.size, 0) /
recent_trades.reduce((s, t) => s + t.size, 0);
return {
symbol,
momentum: parseFloat(momentum.toFixed(6)),
flow: parseFloat(flow_signal.toFixed(4)),
sentiment: internal_signals.sentiment_score,
composite: (
momentum * final_weights.momentum +
flow_signal * final_weights.flow +
internal_signals.sentiment_score * final_weights.sentiment
),
last_updated: quote.timestamp
};
});
// Sort by composite signal strength
signals.sort((a, b) => b.composite - a.composite);
return {
signals,
timestamp: new Date().toISOString(),
weights_applied: final_weights
};
};
module.exports = { handler: buildAlphaComposite };
Note that context.internal is a custom integration point. Enterprise SKILLs can declare additional data sources in their manifest and receive them via context injection.
Private Deployment Strategies
Option 1: Self-Hosted SKILL Runtime
For teams with strict data residency requirements, the SKILL runtime can be deployed on-premises:
# docker-compose.yml for self-hosted SKILL runtime
version: '3.8'
services:
skill-runtime:
image: tickdb/skill-runtime:1.2.0
container_name: enterprise-skill-runtime
environment:
- TICKDB_API_KEY=${TICKDB_API_KEY}
- SKILL_CONFIG_PATH=/app/config/skill.json
- LOG_LEVEL=info
- METRICS_ENABLED=true
- INTERNAL_DATA_ENDPOINT=${INTERNAL_DATA_ENDPOINT}
volumes:
- ./skills:/app/skills
- ./config:/app/config
- ./logs:/app/logs
ports:
- "8080:8080"
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 30s
timeout: 10s
retries: 3
deploy:
resources:
limits:
cpus: '2'
memory: 4G
reservations:
cpus: '0.5'
memory: 1G
The self-hosted runtime provides:
- Data residency: All function execution stays within your network boundary
- Custom data source integration: Point to internal databases, proprietary feeds
- Audit logging: Every function call is logged to your SIEM
- Latency optimization: Co-locate with your trading infrastructure
Option 2: Cloud-Native Enterprise Deployment
For teams prioritizing scalability over data residency:
// enterprise-skill.config.js
module.exports = {
runtime: {
provider: 'aws', // aws | gcp | azure
region: 'us-east-1',
instance_type: 'm5.xlarge',
auto_scaling: {
min: 2,
max: 20,
target_cpu_utilization: 70,
scale_in_cooldown: 300,
scale_out_cooldown: 60
}
},
skills: {
'tickdb-enterprise-skill': {
version: '1.0.0',
functions: [
'get_realtime_quote',
'query_historical',
'calculate_position_size',
'detect_liquidity_regime',
'build_alpha_composite'
],
rate_limit: {
requests_per_minute: 1000,
burst: 200
}
}
},
security: {
authentication: {
type: 'oauth2',
provider: 'okta',
audience: 'tickdb-enterprise'
},
encryption: {
at_rest: true,
in_transit: true,
key_rotation_days: 90
},
audit: {
enabled: true,
sink: 'cloudwatch-logs',
retention_days: 365
}
},
monitoring: {
datadog_integration: true,
error_rate_threshold: 0.01,
p99_latency_threshold_ms: 200
}
};
Option 3: Hybrid Deployment
Many enterprise teams require a hybrid approach—low-latency functions co-located with trading systems, while batch processing runs in the cloud:
┌─────────────────────────────────────────────────────────────┐
│ Enterprise Network │
│ │
│ ┌─────────────────────┐ ┌─────────────────────────┐ │
│ │ Colocation Cluster │ │ Cloud Environment │ │
│ │ │ │ │ │
│ │ SKILL Runtime (HFT) │ │ SKILL Runtime (Batch) │ │
│ │ - Real-time quotes │ │ - Historical analysis │ │
│ │ - Order routing │ │ - Factor computation │ │
│ │ - Risk management │ │ - Backtesting │ │
│ │ │ │ │ │
│ │ Latency: < 5ms │ │ Latency: < 500ms │ │
│ │ Data: Hot cache │ │ Data: TickDB + S3 │ │
│ └─────────────────────┘ └─────────────────────────┘ │
│ │ │ │
│ └────────┬────────────────┘ │
│ ▼ │
│ ┌─────────────────────┐ │
│ │ TickDB API (cloud) │ │
│ │ - Historical klines │ │
│ │ - Symbol metadata │ │
│ │ - Rate limiting │ │
│ └─────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
Production Considerations
Error Handling and Resilience
Every production SKILL function must implement proper error handling:
// functions/get_realtime_quote_with_retry.js
const getRealtimeQuote = async (params, context) => {
const { symbol, max_retries = 3 } = params;
const { logger } = context;
let last_error;
for (let attempt = 0; attempt < max_retries; attempt++) {
try {
const quote = context.tickdb.getQuote(symbol);
// Validate quote integrity
if (!quote.price || !quote.timestamp) {
throw new Error('INVALID_QUOTE: Missing required fields');
}
// Check data freshness (5 second threshold for real-time)
const age_seconds = (Date.now() - quote.timestamp) / 1000;
if (age_seconds > 5) {
logger.warn(`Stale quote for ${symbol}: ${age_seconds.toFixed(1)}s old`);
}
return { success: true, data: quote };
} catch (error) {
last_error = error;
logger.warn(
`Attempt ${attempt + 1}/${max_retries} failed for ${symbol}: ${error.message}`
);
// Exponential backoff
if (attempt < max_retries - 1) {
const delay = Math.min(100 * Math.pow(2, attempt), 2000);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}
logger.error(`All ${max_retries} attempts failed for ${symbol}: ${last_error.message}`);
return {
success: false,
error: last_error.message,
symbol,
attempted_at: new Date().toISOString()
};
};
module.exports = { handler: getRealtimeQuote };
Monitoring and Observability
Deploy SKILL functions with built-in telemetry:
// observability/metrics.js
const recordMetric = (function_name, duration_ms, status, context) => {
const metrics = {
function: function_name,
duration_ms,
status,
timestamp: Date.now(),
instance_id: context.instance_id,
environment: context.environment
};
// Push to your metrics sink
context.metrics.record(metrics);
// Log for debugging
context.logger.info(
`${function_name} completed in ${duration_ms}ms with status ${status}`
);
};
// Usage wrapper for any function
const withMetrics = (handler, function_name) => {
return (params, context) => {
const start = Date.now();
try {
const result = handler(params, context);
recordMetric(function_name, Date.now() - start, 'success', context);
return result;
} catch (error) {
recordMetric(function_name, Date.now() - start, 'error', context);
throw error;
}
};
};
module.exports = { withMetrics };
Deployment Recommendations by Scale
| Use case | Recommended approach | Key consideration |
|---|---|---|
| Individual quant researcher | Standard TickDB API + publicly available SKILLs | Start simple; extend when you hit a wall |
| Small team (2–5 quants) | Cloud-hosted SKILL runtime with shared custom functions | Collaborative versioning via Git |
| Growing desk (5–20 quants) | Dedicated cloud deployment with isolated function namespaces | Team-level rate limits, cost allocation |
| Enterprise (20+ quants) | Hybrid deployment with HFT-optimized on-prem cluster | Data residency, regulatory compliance |
| Multi-strategy fund | Federated deployment with centralized SKILL registry | Governance, audit trails |
Next Steps
If you're an individual quant researcher looking to extend TickDB capabilities, start by reviewing the public SKILL registry at tickdb.ai/skills. Many common use cases are already implemented—only build custom functions when the standard capabilities do not fit your workflow.
If you're a small team building shared tooling, fork the enterprise SKILL template from our GitHub repository (tickdb/enterprise-skill-template) and begin adapting functions for your strategy logic. Use the development configuration (config/development.json) to test against real market data with sandbox credentials.
If you need enterprise-grade features—multi-region failover, custom rate limits, private data source integration, or on-premises deployment—reach out to enterprise@tickdb.ai. Our enterprise team provides white-glove onboarding, dedicated SLAs, and architecture review for high-throughput trading systems.
If you're an AI tooling developer, the SKILL protocol is designed to be AI-agent-native. Search for the tickdb-market-data SKILL in your AI tool's marketplace to get started with zero-configuration integration.
This article does not constitute investment advice. Market data APIs and custom trading tools involve risk; past performance does not guarantee future results. Enterprise deployments should be reviewed by qualified engineering and compliance teams before production use.