DSL v1 schema
The contract every strategy follows. Raw JSON: /method/dsl.json. The validator also enforces what a schema can't: windows are multiples of the timeframe, a buy fits the budget, durations are normalized.
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://dryrun.space/method/dsl.json",
"title": "Dry Run strategy DSL v1",
"type": "object",
"properties": {
"dsl": {
"type": "integer",
"const": 1
},
"name": {
"type": "string",
"maxLength": 60
},
"universe": {
"type": "object",
"properties": {
"mint": {
"type": "string",
"pattern": "^[1-9A-HJ-NP-Za-km-z]{32,44}$"
},
"pair_pool": {
"type": "string",
"pattern": "^[1-9A-HJ-NP-Za-km-z]{32,44}$"
}
},
"required": [
"mint"
],
"additionalProperties": false
},
"timeframe": {
"type": "string",
"enum": [
"1m",
"5m",
"15m",
"1h"
]
},
"budget_usd": {
"type": "number",
"minimum": 10,
"maximum": 1000000
},
"rules": {
"type": "array",
"minItems": 1,
"maxItems": 10,
"items": {
"type": "object",
"properties": {
"when": {
"anyOf": [
{
"type": "object",
"properties": {
"all": {
"type": "array",
"minItems": 1,
"maxItems": 8,
"items": {
"anyOf": [
{
"type": "object",
"description": "Close now vs. the close one window earlier, in percent.",
"properties": {
"metric": {
"type": "string",
"const": "price_change_pct"
},
"window": {
"type": "string",
"pattern": "^[1-9][0-9]{0,3}[mhd]$",
"description": "A count of minutes, hours or days: 5m, 1h, 2d."
},
"op": {
"type": "string",
"enum": [
"<=",
">="
]
},
"value": {
"type": "number",
"minimum": -100,
"maximum": 100000
}
},
"required": [
"metric",
"window",
"op",
"value"
],
"additionalProperties": false
},
{
"type": "object",
"description": "Last close in USD.",
"properties": {
"metric": {
"type": "string",
"const": "price"
},
"op": {
"type": "string",
"enum": [
"<=",
">="
]
},
"value": {
"type": "number",
"exclusiveMinimum": 0,
"description": "USD"
}
},
"required": [
"metric",
"op",
"value"
],
"additionalProperties": false
},
{
"type": "object",
"description": "Market cap estimated at the candle (see /method).",
"properties": {
"metric": {
"type": "string",
"const": "mcap_usd"
},
"op": {
"type": "string",
"enum": [
"<=",
">="
]
},
"value": {
"type": "number",
"minimum": 0,
"description": "USD"
}
},
"required": [
"metric",
"op",
"value"
],
"additionalProperties": false
},
{
"type": "object",
"description": "Pool liquidity estimated at the candle (see /method).",
"properties": {
"metric": {
"type": "string",
"const": "liquidity_usd"
},
"op": {
"type": "string",
"enum": [
"<=",
">="
]
},
"value": {
"type": "number",
"minimum": 0,
"description": "USD"
}
},
"required": [
"metric",
"op",
"value"
],
"additionalProperties": false
},
{
"type": "object",
"description": "Traded volume over the window, in USD.",
"properties": {
"metric": {
"type": "string",
"const": "volume_usd"
},
"window": {
"type": "string",
"pattern": "^[1-9][0-9]{0,3}[mhd]$",
"description": "A count of minutes, hours or days: 5m, 1h, 2d."
},
"op": {
"type": "string",
"enum": [
"<=",
">="
]
},
"value": {
"type": "number",
"minimum": 0,
"description": "USD"
}
},
"required": [
"metric",
"window",
"op",
"value"
],
"additionalProperties": false
},
{
"type": "object",
"description": "How far the close is below the highest high of the window, in percent.",
"properties": {
"metric": {
"type": "string",
"const": "drawdown_from_high_pct"
},
"window": {
"type": "string",
"pattern": "^[1-9][0-9]{0,3}[mhd]$",
"description": "A count of minutes, hours or days: 5m, 1h, 2d."
},
"op": {
"type": "string",
"const": ">="
},
"value": {
"type": "number",
"exclusiveMinimum": 0,
"maximum": 100
}
},
"required": [
"metric",
"window",
"op",
"value"
],
"additionalProperties": false
},
{
"type": "object",
"description": "Whether a simulated position is open.",
"properties": {
"metric": {
"type": "string",
"const": "position_open"
},
"value": {
"type": "boolean"
}
},
"required": [
"metric",
"value"
],
"additionalProperties": false
},
{
"type": "object",
"description": "Open position's value at the close vs. its cost basis, in percent. False when no position is open.",
"properties": {
"metric": {
"type": "string",
"const": "position_pnl_pct"
},
"op": {
"type": "string",
"enum": [
"<=",
">="
]
},
"value": {
"type": "number",
"minimum": -100,
"maximum": 100000
}
},
"required": [
"metric",
"op",
"value"
],
"additionalProperties": false
},
{
"type": "object",
"description": "Time since the open position's first buy fill. False when no position is open.",
"properties": {
"metric": {
"type": "string",
"const": "time_in_position"
},
"op": {
"type": "string",
"const": ">="
},
"value": {
"type": "string",
"pattern": "^[1-9][0-9]{0,3}[mhd]$",
"description": "A count of minutes, hours or days: 5m, 1h, 2d."
}
},
"required": [
"metric",
"op",
"value"
],
"additionalProperties": false
},
{
"type": "object",
"description": "Simulated cash not in a position.",
"properties": {
"metric": {
"type": "string",
"const": "budget_left_usd"
},
"op": {
"type": "string",
"const": ">="
},
"value": {
"type": "number",
"minimum": 0,
"description": "USD"
}
},
"required": [
"metric",
"op",
"value"
],
"additionalProperties": false
}
]
}
}
},
"required": [
"all"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"any": {
"type": "array",
"minItems": 1,
"maxItems": 8,
"items": {
"anyOf": [
{
"type": "object",
"description": "Close now vs. the close one window earlier, in percent.",
"properties": {
"metric": {
"type": "string",
"const": "price_change_pct"
},
"window": {
"type": "string",
"pattern": "^[1-9][0-9]{0,3}[mhd]$",
"description": "A count of minutes, hours or days: 5m, 1h, 2d."
},
"op": {
"type": "string",
"enum": [
"<=",
">="
]
},
"value": {
"type": "number",
"minimum": -100,
"maximum": 100000
}
},
"required": [
"metric",
"window",
"op",
"value"
],
"additionalProperties": false
},
{
"type": "object",
"description": "Last close in USD.",
"properties": {
"metric": {
"type": "string",
"const": "price"
},
"op": {
"type": "string",
"enum": [
"<=",
">="
]
},
"value": {
"type": "number",
"exclusiveMinimum": 0,
"description": "USD"
}
},
"required": [
"metric",
"op",
"value"
],
"additionalProperties": false
},
{
"type": "object",
"description": "Market cap estimated at the candle (see /method).",
"properties": {
"metric": {
"type": "string",
"const": "mcap_usd"
},
"op": {
"type": "string",
"enum": [
"<=",
">="
]
},
"value": {
"type": "number",
"minimum": 0,
"description": "USD"
}
},
"required": [
"metric",
"op",
"value"
],
"additionalProperties": false
},
{
"type": "object",
"description": "Pool liquidity estimated at the candle (see /method).",
"properties": {
"metric": {
"type": "string",
"const": "liquidity_usd"
},
"op": {
"type": "string",
"enum": [
"<=",
">="
]
},
"value": {
"type": "number",
"minimum": 0,
"description": "USD"
}
},
"required": [
"metric",
"op",
"value"
],
"additionalProperties": false
},
{
"type": "object",
"description": "Traded volume over the window, in USD.",
"properties": {
"metric": {
"type": "string",
"const": "volume_usd"
},
"window": {
"type": "string",
"pattern": "^[1-9][0-9]{0,3}[mhd]$",
"description": "A count of minutes, hours or days: 5m, 1h, 2d."
},
"op": {
"type": "string",
"enum": [
"<=",
">="
]
},
"value": {
"type": "number",
"minimum": 0,
"description": "USD"
}
},
"required": [
"metric",
"window",
"op",
"value"
],
"additionalProperties": false
},
{
"type": "object",
"description": "How far the close is below the highest high of the window, in percent.",
"properties": {
"metric": {
"type": "string",
"const": "drawdown_from_high_pct"
},
"window": {
"type": "string",
"pattern": "^[1-9][0-9]{0,3}[mhd]$",
"description": "A count of minutes, hours or days: 5m, 1h, 2d."
},
"op": {
"type": "string",
"const": ">="
},
"value": {
"type": "number",
"exclusiveMinimum": 0,
"maximum": 100
}
},
"required": [
"metric",
"window",
"op",
"value"
],
"additionalProperties": false
},
{
"type": "object",
"description": "Whether a simulated position is open.",
"properties": {
"metric": {
"type": "string",
"const": "position_open"
},
"value": {
"type": "boolean"
}
},
"required": [
"metric",
"value"
],
"additionalProperties": false
},
{
"type": "object",
"description": "Open position's value at the close vs. its cost basis, in percent. False when no position is open.",
"properties": {
"metric": {
"type": "string",
"const": "position_pnl_pct"
},
"op": {
"type": "string",
"enum": [
"<=",
">="
]
},
"value": {
"type": "number",
"minimum": -100,
"maximum": 100000
}
},
"required": [
"metric",
"op",
"value"
],
"additionalProperties": false
},
{
"type": "object",
"description": "Time since the open position's first buy fill. False when no position is open.",
"properties": {
"metric": {
"type": "string",
"const": "time_in_position"
},
"op": {
"type": "string",
"const": ">="
},
"value": {
"type": "string",
"pattern": "^[1-9][0-9]{0,3}[mhd]$",
"description": "A count of minutes, hours or days: 5m, 1h, 2d."
}
},
"required": [
"metric",
"op",
"value"
],
"additionalProperties": false
},
{
"type": "object",
"description": "Simulated cash not in a position.",
"properties": {
"metric": {
"type": "string",
"const": "budget_left_usd"
},
"op": {
"type": "string",
"const": ">="
},
"value": {
"type": "number",
"minimum": 0,
"description": "USD"
}
},
"required": [
"metric",
"op",
"value"
],
"additionalProperties": false
}
]
}
}
},
"required": [
"any"
],
"additionalProperties": false
}
]
},
"then": {
"anyOf": [
{
"type": "object",
"properties": {
"action": {
"type": "string",
"const": "buy_usd"
},
"usd": {
"type": "number",
"exclusiveMinimum": 0,
"description": "USD to spend, fees included"
}
},
"required": [
"action",
"usd"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"action": {
"type": "string",
"const": "buy_pct_of_budget"
},
"pct": {
"type": "number",
"exclusiveMinimum": 0,
"maximum": 100,
"description": "Percent of budget_usd (the starting budget)"
}
},
"required": [
"action",
"pct"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"action": {
"type": "string",
"const": "sell_pct_of_position"
},
"pct": {
"type": "number",
"exclusiveMinimum": 0,
"maximum": 100,
"description": "Percent of the open position's tokens"
}
},
"required": [
"action",
"pct"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"action": {
"type": "string",
"const": "sell_all"
}
},
"required": [
"action"
],
"additionalProperties": false
}
]
},
"once": {
"type": "boolean"
},
"cooldown": {
"type": "string",
"pattern": "^[1-9][0-9]{0,3}[mhd]$",
"description": "A count of minutes, hours or days: 5m, 1h, 2d."
},
"label": {
"type": "string",
"maxLength": 40
}
},
"required": [
"when",
"then"
],
"additionalProperties": false
},
"description": "Ordered; the first rule that matches and can execute wins."
},
"risk": {
"type": "object",
"description": "Always applied after the rules.",
"properties": {
"stop_loss_pct": {
"type": "number",
"exclusiveMinimum": 0,
"maximum": 100,
"description": "Sell everything when position P&L ≤ −this"
},
"take_profit_pct": {
"type": "number",
"exclusiveMinimum": 0,
"maximum": 100000,
"description": "Sell everything when position P&L ≥ this"
},
"trailing_stop_pct": {
"type": "number",
"exclusiveMinimum": 0,
"maximum": 100,
"description": "Sell everything when the close falls this far below the highest close since entry"
},
"max_position_usd": {
"type": "number",
"exclusiveMinimum": 0,
"description": "Cap on the open position's cost basis"
},
"max_buys": {
"type": "integer",
"minimum": 1,
"maximum": 100,
"description": "Cap on buy fills per open position"
}
},
"required": [],
"additionalProperties": false
},
"costs": {
"type": "object",
"properties": {
"dex_fee_pct": {
"type": "number",
"minimum": 0,
"maximum": 10
},
"network_fee_sol": {
"type": "number",
"minimum": 0,
"maximum": 0.01
}
},
"required": [],
"additionalProperties": false
}
},
"required": [
"dsl",
"universe",
"timeframe",
"budget_usd",
"rules",
"risk"
],
"additionalProperties": false
}