This quickstart takes you from zero to a production-ready, MiCA-compliant trading bot.
Time: ~30 minutes
Prerequisites: Node.js 18+, Kubernetes cluster or Docker, Kakunin account
Go to dashboard.kakunin.ai and sign up. You'll get:
Set up environment variables:
# .env.local
KAKUNIN_API_KEY=sk_live_xxxxxxxxxxxxxxxx
KAKUNIN_PROJECT_ID=proj_1234567890
AWS_REGION=eu-west-1 # Use EU region for GDPR
KMS_CA_KEY_ARN=arn:aws:kms:eu-west-1:123456789:key/12345678-1234-1234-1234-123456789012
Create a policy file that matches your regulatory requirements:
// mica-policy.ts
const micaPolicy = {
agentName: 'algo_trader_v2',
operatorName: 'your_company_ltd',
operatorRegulatorId: 'FINMA-123456', // Your regulatory registration
// MiCA scope limits
scope: {
maxTradeSize: 25000, // EUR per trade
maxDailyVolume: 500000, // EUR per day
allowedMarkets: ['EUR_USD', 'GBP_EUR'], // Only these pairs
tradingHours: {
start: '08:00',
end: '17:00',
tz: 'UTC',
excludeWeekends: true,
},
allowedRegions: ['eu-west-1'], // GDPR compliance
},
// Risk controls
riskControls: {
killSwitchAutomatic: 'anomaly_0.85', // Revoke if anomaly > 0.85
circuitBreakerThreshold: 0.75,
maxConsecutiveFailures: 3,
},
// Documentation (for regulators)
governance: {
boardApprovedDate: '2026-05-01',
nextAuditDate: '2026-08-01',
},
};
export default micaPolicy;
npm install @kakunin/sdk @kakunin/trading-bot axios dotenv
// src/agent/bootstrap.ts
import { KakuninClient } from '@kakunin/sdk';
import micaPolicy from '../mica-policy';
const kakunin = new KakuninClient({
apiKey: process.env.KAKUNIN_API_KEY,
baseUrl: 'https://api.kakunin.ai',
});
export async function bootstrapAgent() {
// Create or retrieve agent
const agent = await kakunin.agents.create({
name: micaPolicy.agentName,
metadata: {
version: '2.1.0',
deployment: 'kubernetes',
operator: micaPolicy.operatorName,
regulatorId: micaPolicy.operatorRegulatorId,
},
});
console.log(`✓ Agent created: ${agent.id}`);
// Issue X.509 certificate with MiCA scope
const cert = await kakunin.agents.getCertificate(agent.id, {
validityDays: 365,
scope: micaPolicy.scope,
});
console.log(`✓ Certificate issued: ${cert.serial_number}`);
// Store certificate and KMS ARN
const identity = {
agentId: agent.id,
certificatePem: cert.certificate_pem,
kmsKeyArn: cert.kms_key_arn,
serialNumber: cert.serial_number,
};
// Save to secure location (not in code!)
await saveToSecretManager(identity);
return identity;
}
async function saveToSecretManager(identity: any) {
// Use Kubernetes Secrets, AWS Secrets Manager, or equivalent
// NEVER hardcode credentials
console.log('Saving identity to secret manager...');
}
// src/agent/trading-engine.ts
import { KakuninClient } from '@kakunin/sdk';
import axios from 'axios';
const kakunin = new KakuninClient({
apiKey: process.env.KAKUNIN_API_KEY,
});
export async function executeTrade(
identity: any,
tradeRequest: {
market: string;
side: 'BUY' | 'SELL';
size: number;
}
) {
// Step 1: Serialize trade request deterministically
const payload = JSON.stringify(tradeRequest, Object.keys(tradeRequest).sort());
// Step 2: Pre-trade risk check (run before signing)
const preTradeCheck = await kakunin.trading.preTradeRiskCheck({
agentId: identity.agentId,
payload,
});
if (!preTradeCheck.allowed) {
console.error(`❌ Trade blocked: ${preTradeCheck.reason}`, preTradeCheck);
return { error: preTradeCheck.reason };
}
console.log(`✓ Pre-trade check passed, anomaly score: ${preTradeCheck.anomalyScore}`);
// Step 3: Sign the trade with agent's identity
const signed = await kakunin.actions.sign({
agentId: identity.agentId,
payload,
metadata: {
actionType: 'trade.execute',
timestamp: Date.now(),
},
});
console.log(`✓ Trade signed (signature: ${signed.signature.substring(0, 20)}...)`);
// Step 4: Submit to exchange with proof of identity
const response = await axios.post('https://api.exchange.com/v1/trades', tradeRequest, {
headers: {
'Content-Type': 'application/json',
'X-Agent-Certificate': identity.certificatePem,
'X-Agent-Signature': signed.signature,
'X-Agent-Timestamp': signed.timestamp.toString(),
'Authorization': `Bearer ${process.env.EXCHANGE_API_KEY}`,
},
});
if (response.status !== 200) {
console.error(`❌ Exchange rejected trade: ${response.data}`);
return { error: 'exchange_rejected' };
}
// Step 5: Log the trade (for MiCA audit trail)
await logTrade(identity, tradeRequest, signed, response.data);
console.log(`✓ Trade executed: ${response.data.orderId}`);
return response.data;
}
async function logTrade(identity: any, request: any, signed: any, result: any) {
const auditEntry = {
timestamp: new Date().toISOString(),
agentId: identity.agentId,
agentCertSerial: identity.serialNumber,
orderId: result.orderId,
market: request.market,
side: request.side,
size: request.size,
executionPrice: result.executionPrice,
signature: signed.signature.substring(0, 50) + '...',
signatureVerified: true,
};
console.log('📋 Audit log:', JSON.stringify(auditEntry, null, 2));
// Store in audit log (WORM — write-once, read-many)
// This is your evidence for regulators
}
// src/agent/kya-setup.ts
import { KakuninClient } from '@kakunin/sdk';
const kakunin = new KakuninClient({
apiKey: process.env.KAKUNIN_API_KEY,
});
export async function setupKYABaseline(agentId: string) {
// Define baseline (based on your trading algorithm's expected behavior)
const baseline = {
agentId,
// Median trade size from historical testing
transactionSizeP50: 18500, // EUR
transactionSizeP99: 24000, // EUR (approach limit)
// Expected frequency
transactionsPerHour: 6, // Median
transactionsPerHourP95: 15, // Peak
// Market preferences
preferredMarkets: ['EUR_USD', 'GBP_EUR'],
// Time patterns
tradingHours: {
start: 8, // 08:00 UTC
end: 17, // 17:00 UTC
excludeWeekends: true,
},
};
// Register baseline
const result = await kakunin.monitoring.setBaseline(agentId, baseline);
console.log(`✓ KYA baseline set, anomaly detection armed`);
return baseline;
}
# k8s/trading-bot.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: algo-trader
spec:
replicas: 1
selector:
matchLabels:
app: algo-trader
template:
metadata:
labels:
app: algo-trader
spec:
serviceAccountName: algo-trader
containers:
- name: trading-bot
image: myrepo/algo-trader:v2
env:
- name: KAKUNIN_API_KEY
valueFrom:
secretKeyRef:
name: kakunin-secrets
key: api-key
- name: KAKUNIN_PROJECT_ID
value: proj_1234567890
- name: EXCHANGE_API_KEY
valueFrom:
secretKeyRef:
name: exchange-secrets
key: api-key
volumeMounts:
- name: agent-identity
mountPath: /var/secrets/agent
readOnly: true
- name: audit-logs
mountPath: /var/audit
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
volumes:
- name: agent-identity
secret:
secretName: agent-certificate
- name: audit-logs
persistentVolumeClaim:
claimName: audit-logs-pvc
Deploy:
kubectl apply -f k8s/trading-bot.yaml
kubectl rollout status deployment/algo-trader -w
# Check agent is running
kubectl logs -f deployment/algo-trader
# Expected output:
# ✓ Agent created: agent_12345
# ✓ Certificate issued: F1D4E8C7B2A9F3E6
# ✓ KYA baseline set, anomaly detection armed
# Waiting for trading signals...
# Port forward to local for testing
kubectl port-forward svc/algo-trader 8080:8080
# Test health check
curl http://localhost:8080/health
# Expected: {"status": "ok", "anomalyScore": 0.05}
Create a folder with:
/regulatory-docs
├── board-resolution.pdf # Board approved this deployment
├── mica-policy.json # Scope policy + governance framework
├── baseline-profile.json # Behavioral baseline (7-day period)
├── certificate-chain.pem # Full X.509 certificate chain
├── sample-audit-logs.json # First 10 trades with signatures
├── incident-response-plan.md # What happens if anomaly detected
└── testing-schedule.md # Annual fitness tests scheduled
Submit to your regulator. You now have:
// src/monitoring/dashboard.ts
import { KakuninClient } from '@kakunin/sdk';
const kakunin = new KakuninClient({
apiKey: process.env.KAKUNIN_API_KEY,
});
setInterval(async () => {
const agentStatus = await kakunin.monitoring.getAgentStatus(agentId);
console.log(`
Agent: ${agentStatus.agentId}
Cert: ${agentStatus.certificateStatus} (valid/${agentStatus.daysUntilExpiry} days)
Anomaly Score: ${agentStatus.anomalyScore}
Trades Today: ${agentStatus.tradesExecuted}/${agentStatus.dailyLimit}
Median Size: €${agentStatus.medianTradeSize}
Last Trade: ${agentStatus.lastTradeTime}
`);
// If anomaly score rises above 0.75, you'll get a warning
if (agentStatus.anomalyScore > 0.75) {
console.warn('⚠️ Anomaly threshold exceeded. Check logs.');
}
}, 60000); // Check every minute
Your trading bot is now:
Next: Go through the MiCA case study to see what happens when the bot behaves anomalously.
Questions? See the MiCA compliance deep dive for regulatory details.