Getting started
All endpoints live under /v1. Send JSON bodies with
Content-Type: application/json and authenticate with
a Bearer token. Request a key from the
pricing page.
Base URL
https://replicurve.com/v1
Authentication
Include your API key on every request:
Authorization: Bearer <your-api-key>
Quick example
Submit aligned daily return series for the target. On Starter plans,
basket is a preset universe name (string). On
Professional plans and above, basket is return series
keyed by ticker. Tune config.max_allocation and
config.rebalance_freq as needed.
Custom basket (Professional+)
import os
import requests
response = requests.post(
"https://replicurve.com/v1/replication",
headers={"Authorization": f"Bearer {os.environ['API_KEY']}"},
json={
"target": {
"returns": [
{"date": "2024-01-02", "value": 0.0012},
{"date": "2024-01-03", "value": -0.0008},
]
},
"basket": {
"AAPL": [
{"date": "2024-01-02", "value": 0.0021},
{"date": "2024-01-03", "value": -0.0015},
]
},
"config": {"max_allocation": 10, "rebalance_freq": "weekly"},
},
)
response.raise_for_status()
print(response.json())
const response = await fetch("https://replicurve.com/v1/replication", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
target: {
returns: [
{ date: "2024-01-02", value: 0.0012 },
{ date: "2024-01-03", value: -0.0008 },
],
},
basket: {
AAPL: [
{ date: "2024-01-02", value: 0.0021 },
{ date: "2024-01-03", value: -0.0015 },
],
},
config: { max_allocation: 10, rebalance_freq: "weekly" },
}),
});
if (!response.ok) throw new Error(await response.text());
console.log(await response.json());
#include <curl/curl.h>
#include <cstdlib>
#include <iostream>
#include <string>
int main() {
const char* url = "https://replicurve.com/v1/replication";
const char* api_key = std::getenv("API_KEY");
const std::string body = R"({
"target": {
"returns": [
{"date": "2024-01-02", "value": 0.0012},
{"date": "2024-01-03", "value": -0.0008}
]
},
"basket": {
"AAPL": [
{"date": "2024-01-02", "value": 0.0021},
{"date": "2024-01-03", "value": -0.0015}
]
},
"config": {"max_allocation": 10, "rebalance_freq": "weekly"}
})";
CURL* curl = curl_easy_init();
struct curl_slist* headers = nullptr;
headers = curl_slist_append(
headers, ("Authorization: Bearer " + std::string(api_key)).c_str());
headers = curl_slist_append(headers, "Content-Type: application/json");
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body.c_str());
CURLcode res = curl_easy_perform(curl);
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
return res == CURLE_OK ? 0 : 1;
}
use std::env;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let api_key = env::var("API_KEY")?;
let client = reqwest::Client::new();
let body = serde_json::json!({
"target": {
"returns": [
{"date": "2024-01-02", "value": 0.0012},
{"date": "2024-01-03", "value": -0.0008}
]
},
"basket": {
"AAPL": [
{"date": "2024-01-02", "value": 0.0021},
{"date": "2024-01-03", "value": -0.0015}
]
},
"config": {"max_allocation": 10, "rebalance_freq": "weekly"}
});
let response = client
.post("https://replicurve.com/v1/replication")
.header("Authorization", format!("Bearer {}", api_key))
.json(&body)
.send()
.await?;
println!("{}", response.text().await?);
Ok(())
}
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class ReplicationExample {
public static void main(String[] args) throws Exception {
String apiKey = System.getenv("API_KEY");
String body = """
{
"target": {
"returns": [
{"date": "2024-01-02", "value": 0.0012},
{"date": "2024-01-03", "value": -0.0008}
]
},
"basket": {
"AAPL": [
{"date": "2024-01-02", "value": 0.0021},
{"date": "2024-01-03", "value": -0.0015}
]
},
"config": {"max_allocation": 10, "rebalance_freq": "weekly"}
}
""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://replicurve.com/v1/replication"))
.header("Authorization", "Bearer " + apiKey)
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
}
}
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
var apiKey = Environment.GetEnvironmentVariable("API_KEY");
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", apiKey);
var body = """
{
"target": {
"returns": [
{"date": "2024-01-02", "value": 0.0012},
{"date": "2024-01-03", "value": -0.0008}
]
},
"basket": {
"AAPL": [
{"date": "2024-01-02", "value": 0.0021},
{"date": "2024-01-03", "value": -0.0015}
]
},
"config": {"max_allocation": 10, "rebalance_freq": "weekly"}
}
""";
var response = await client.PostAsync(
"https://replicurve.com/v1/replication",
new StringContent(body, Encoding.UTF8, "application/json"));
Console.WriteLine(await response.Content.ReadAsStringAsync());
Starter (preset universe)
import os
import requests
response = requests.post(
"https://replicurve.com/v1/replication",
headers={"Authorization": f"Bearer {os.environ['API_KEY']}"},
json={
"target": {
"returns": [
{"date": "2024-01-02", "value": 0.0012},
{"date": "2024-01-03", "value": -0.0008},
]
},
"basket": "sp500",
"config": {"max_allocation": 10, "rebalance_freq": "weekly"},
},
)
response.raise_for_status()
print(response.json())
const response = await fetch("https://replicurve.com/v1/replication", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
target: {
returns: [
{ date: "2024-01-02", value: 0.0012 },
{ date: "2024-01-03", value: -0.0008 },
],
},
basket: "sp500",
config: { max_allocation: 10, rebalance_freq: "weekly" },
}),
});
if (!response.ok) throw new Error(await response.text());
console.log(await response.json());
#include <curl/curl.h>
#include <cstdlib>
#include <iostream>
#include <string>
int main() {
const char* url = "https://replicurve.com/v1/replication";
const char* api_key = std::getenv("API_KEY");
const std::string body = R"({
"target": {
"returns": [
{"date": "2024-01-02", "value": 0.0012},
{"date": "2024-01-03", "value": -0.0008}
]
},
"basket": "sp500",
"config": {"max_allocation": 10, "rebalance_freq": "weekly"}
})";
CURL* curl = curl_easy_init();
struct curl_slist* headers = nullptr;
headers = curl_slist_append(
headers, ("Authorization: Bearer " + std::string(api_key)).c_str());
headers = curl_slist_append(headers, "Content-Type: application/json");
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body.c_str());
CURLcode res = curl_easy_perform(curl);
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
return res == CURLE_OK ? 0 : 1;
}
use std::env;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let api_key = env::var("API_KEY")?;
let client = reqwest::Client::new();
let body = serde_json::json!({
"target": {
"returns": [
{"date": "2024-01-02", "value": 0.0012},
{"date": "2024-01-03", "value": -0.0008}
]
},
"basket": "sp500",
"config": {"max_allocation": 10, "rebalance_freq": "weekly"}
});
let response = client
.post("https://replicurve.com/v1/replication")
.header("Authorization", format!("Bearer {}", api_key))
.json(&body)
.send()
.await?;
println!("{}", response.text().await?);
Ok(())
}
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class ReplicationExample {
public static void main(String[] args) throws Exception {
String apiKey = System.getenv("API_KEY");
String body = """
{
"target": {
"returns": [
{"date": "2024-01-02", "value": 0.0012},
{"date": "2024-01-03", "value": -0.0008}
]
},
"basket": "sp500",
"config": {"max_allocation": 10, "rebalance_freq": "weekly"}
}
""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://replicurve.com/v1/replication"))
.header("Authorization", "Bearer " + apiKey)
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
}
}
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
var apiKey = Environment.GetEnvironmentVariable("API_KEY");
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", apiKey);
var body = """
{
"target": {
"returns": [
{"date": "2024-01-02", "value": 0.0012},
{"date": "2024-01-03", "value": -0.0008}
]
},
"basket": "sp500",
"config": {"max_allocation": 10, "rebalance_freq": "weekly"}
}
""";
var response = await client.PostAsync(
"https://replicurve.com/v1/replication",
new StringContent(body, Encoding.UTF8, "application/json"));
Console.WriteLine(await response.Content.ReadAsStringAsync());
Endpoints
/v1/health
Health check
/v1/usage
Monthly call count
/v1/replication
Run replication
/v1/offset
Run offset
/v1/validate
Validate inputs
Request parameters
POST /v1/replication, POST /v1/offset, and
POST /v1/validate share the same JSON body. Returns are
daily simple returns (not log returns or prices). Each basket series
must use exactly the same calendar dates as target.returns.
Top-level fields
| Field | Type | Required | Description |
|---|---|---|---|
target |
object | yes | Return series to replicate or offset. |
target.returns |
array | yes |
At least two daily observations. Each element has
date (ISO 8601, e.g. 2024-01-02)
and value (simple daily return as a decimal, e.g. 0.0012
for +0.12%).
|
basket |
string or object | yes | Candidate instruments. A string selects a preset universe (Starter plans). An object maps ticker labels to return arrays (Professional plans and above). See basket formats below. |
config |
object | no | Replication settings. Omitted fields use the defaults in config fields. |
Config fields
All fields live under config and are optional.
| Field | Type | Default | Description |
|---|---|---|---|
rebalance_freq |
"daily" | "weekly" |
"weekly" |
How often the engine recomputes portfolio weights. Weekly rebalances use a one-day implementation lag. |
max_allocation |
integer ≥ 1 | 10 |
Maximum number of basket names held at any rebalance date. The engine prescreens candidates by trailing correlation before selecting up to this count. |
direction |
"long" | "short" | "long_short" |
"long_short" |
Position sign constraint applied during weight estimation.
long clips to non-negative weights,
short to non-positive, and
long_short allows both.
|
weight_normalization |
"none" | "gross" |
"none" |
Post-processing on each weight snapshot in the response.
gross scales weights so absolute values sum
to 1; none returns raw estimated weights.
|
Basket formats
| Format | Plans | Description |
|---|---|---|
| Preset universe string | Starter+ |
One of sp500, nasdaq100,
ftse100, us_listed_etfs, or
ucits_etfs. The service loads aligned daily
returns for every name in that universe.
|
| Custom return series | Professional+ |
Object keyed by ticker label. Each value is a
returns array with the same dates and length
as target.returns. Labels must be non-empty
strings; each series needs at least two points.
|
Endpoint behavior
| Endpoint | Effect |
|---|---|
POST /v1/replication |
Estimates time-varying weights that track the target return series. Returns weights, aligned return series, and tracking metrics. |
POST /v1/offset |
Same request body as replication. The engine negates the target returns before optimization, producing weights intended to neutralize target exposure. |
POST /v1/validate |
Checks date alignment, missing values, and whether the overlapping history meets the rolling-window requirement (66 trading days by default). Does not run the full optimization. |
GET /v1/usage |
Returns the authenticated key's monthly
POST /v1/replication and
POST /v1/offset count, plan allowance, and
remaining calls for the current calendar month. Does not
increment usage.
|
Response fields
Replication and offset (ReplicationResponse)
| Field | Type | Description |
|---|---|---|
weights |
array |
Sparse rebalance snapshots. Each element has
date and weights (ticker →
weight). Only dates where the portfolio changes are
included; zero weights are omitted.
|
target |
array | Aligned target return series used in the run (same shape as input, after alignment). |
portfolio |
array | Simulated portfolio return series produced by applying the estimated weights to the basket. |
metrics |
object | Sample period, tracking quality, return statistics, and allocation summary. See below. |
metrics
| Field | Description |
|---|---|
start, end, observations, period |
Aligned comparison window and return frequency. |
correlation, r_squared, beta, alpha_annual |
Tracking quality versus the target series. |
tracking_error, information_ratio, hit_rate, mean_error, slippage |
Active return and error statistics. |
target_* and portfolio_* return fields |
Paired statistics (total_return, cagr, volatility, sharpe, max_drawdown) for target and portfolio. |
avg_assets, turnover, gross_exposure |
Allocation summary over active rebalance dates. |
Validate (ValidationResponse)
| Field | Description |
|---|---|
valid |
true when inputs pass alignment and window checks; false otherwise. |
overlapping_days |
Number of dates with non-missing target and basket data. |
basket_size |
Count of basket series after resolution (preset universes expand to their full membership). |
message |
Human-readable outcome. On failure, describes the validation error. |
Health (HealthResponse)
| Field | Description |
|---|---|
status |
Service health indicator (ok when the engine is reachable). |
version |
Deployed engine package version. |
Replication and offset methodology
High-level overview with live tracking statistics and charts from all ten site examples. Proprietary estimation details are intentionally omitted.
Download the whitepaper (PDF)
~10 pages — methodology, tracking metrics, and charts for every site example.
OpenAPI specification
Rendered from /assets/openapi.json, exported from the
FastAPI app at deploy time.