Skip to main content

Metrics

In the Almanak Strategy Framework, there are 2 types of Metrics: System-Level & Strategy-Level metrics. The system-level metrics are logged and stored automatically by the stack, for example each time an Action is executed, a metrics is stored saving the executed details of that action. These metrics are "free", in the sense that the user doesn't have anything to do to log them, it happens automatically. The strategy-level, or custom, metrics are the responsibility of the user (i.e. the strategist) to define them and implement them in the strategy code.

A metric can be pretty much any information stored in a json format. All metrics are stored in our metrics database and can later be fetched for analytics and dashboard purposes.

The Strategy-Level Metrics should be implemented in a metrics.py file in the root folder of the strategy (e.g. /MyStrategy/metrics.py), where the strategy.py and models.py live. If no custom metrics are define, then the metrics.py is not required.

For example if the user wants to create a custom metric to log the CEX price and the DEX price after a swap to compare the spread between the two:

./MyStrategy/metrics.py

# metrics.py

from src.almanak_library.metrics.metrics_agg import MetricAggType, MetricsAggTable
from src.strategy.utils.price_volatility import get_current_price
from src.strategy.utils.utils import DataSource

def log_strategy_spread_metrics(strat, action):
try:
# Get current price of WBTC/WETH - A 3-way example with USD intermediate (when the pair is not directly available)
token0_usd = get_current_price(
data_source=DataSource.BINANCE,
base_symbol=strat.token0_symbol,
quote_symbol="USD",
)
token1_usd = get_current_price(
data_source=DataSource.BINANCE,
base_symbol=strat.token1_symbol,
quote_symbol="USD",
)
cex_price = token0_usd / token1_usd

dex_price = strat.uniswap_v3.get_pool_spot_rate(pool_address=strat.pool_address)

# Metrics details json payload
details = {
"cex_price": cex_price,
"dex_price": dex_price,
}

strat.metrics_agg_handler.add_metric(
MetricsAggTable(
metric_type="SPREAD",
strategy_id=strat.id,
wallet_address=strat.wallet_address,
details=details,
action_id=str(action.id),
bundle_id=str(action.bundle_id),
block_number=int(action.execution_details.block_number),
)
)
except Exception as e:
print(
f"Error logging strategy spread metrics: {e}"
)

./MyStrategy/states/swap.py

from src.strategy.strategies.my_strategy.metrics import log_strategy_spread_metrics

# swap.py -- state file
def validate_swap(strat):

...

# Find the swap action
swap_actions = [action for action in actions.actions if action.type == ActionType.SWAP]
if len(swap_actions) != 1:
raise ValueError(f"Validation failed (Swap): Expected 1 swap action, found: {len(swap_actions)}")
swap_action = swap_actions[0]

# Triggering the log metric function
try:
log_strategy_spread_metrics(strat, swap_action)
except Exception as e:
print("Spread Metric logging failed.")

Important Instructions:

  1. A Metric must be associated with an Action (and therefore an ActionBundle). That ensures the uniqueness in the DB.
  2. It is a good pratice to wrap the log_strategy_x_metrics() function call into a try/except to avoid the strategy crashing if the metrics can't be logged, unless metrics are crucial. In most cases we concider

Here is an example of a WRAP Metric (an Action, system-level metric) in the Database:

{
"metrics_action": [
{
"id" : 1023,
"time" : "2025-02-26T12:34:15.662192+00:00",
"block_number" : 21930230,
"metric_type" : "WRAP",
"strategy_id" : "BLUECHIP_PENDLE_WETH",
"action_id" : "a4f86442-eea7-4904-8805-3be64ebfdf23",
"bundle_id" : "955a8473-9c53-46fb-8d31-27bee0784fd5",
"wallet_address" : "0xc1f07f25904Bc693c5bB975C23cF0176722E1c8E",
"details" : "{\"bundle_id\": \"955a8473-9c53-46fb-8d31-27bee0784fd5\", \"tx_cost\": 87333540086576, \"gas_used\": 86576, \"block_number\": 21930230, \"amount\": 2029913350346602}",
"agent_id" : "de512eb4-9490-4542-a16a-69624d8e7f4c",
"user_id" : "725c4b09-a806-42b1-ced1-3e7bcc2338d4"
}
]}

Here is an example of a GAS Metric (an Action, system-level metric) in the Database:

{
"metrics_action": [
{
"id" : 1024,
"time" : "2025-02-26T12:34:15.988071+00:00",
"block_number" : 21930230,
"metric_type" : "GAS",
"strategy_id" : "BLUECHIP_PENDLE_WETH",
"action_id" : "a4f86442-eea7-4904-8805-3be64ebfdf23",
"bundle_id" : "955a8473-9c53-46fb-8d31-27bee0784fd5",
"wallet_address" : "0xc1f07f25904Bc693c5bB975C23cF0176722E1c8E",
"details" : "{\"function\": \"WRAP\", \"gas_used\": 86576, \"tx_cost\": 87333540086576}",
"agent_id" : "de512eb4-9490-4542-a16a-69624d8e7f4c",
"user_id" : "725c4b09-a806-42b1-ced1-3e7bcc2338d4"
}
]}

Here is an example of a SWAP Metric (an Action, system-level metric) in the Database:

{
"metrics_action": [
{
"id" : 114,
"time" : "2025-02-26T20:08:13.729554+00:00",
"block_number" : 310203649,
"metric_type" : "SWAP",
"strategy_id" : "BLUECHIP_PENDLE_WETH",
"action_id" : "0e6173d8-ba16-4ca6-afb0-cf795477790e",
"bundle_id" : "880119d6-5e20-4b83-bb4c-8454a605227c",
"wallet_address" : "0xc1f07f25904Bc693c5bB975C23cF0176722E1c8E",
"details" : "{\"bundle_id\": \"880119d6-5e20-4b83-bb4c-8454a605227c\", \"tx_cost\": 6291016983000, \"gas_used\": 172721, \"block_number\": 310203649, \"side\": \"SELL\", \"tokenIn_symbol\": \"PENDLE\", \"tokenOut_symbol\": \"WETH\", \"amountIn\": 406822341012480846, \"amountOut\": 474836860869367}",
"agent_id" : "7446ccae-25a7-423f-a436-6f0bcca5d28e",
"user_id" : "725c4b09-a806-42b1-cd12-3e7bcc2338d4"
}
]}

Here is an example of an OPEN_POSITION Metric (an Action, system-level metric) in the Database:

{
"metrics_action": [
{
"id" : 120,
"time" : "2025-02-26T20:08:39.909372+00:00",
"block_number" : 310203737,
"metric_type" : "OPEN_POSITION",
"strategy_id" : "BLUECHIP_PENDLE_WETH",
"action_id" : "670c2dc4-7c62-494b-97b0-737bbb32edf2",
"bundle_id" : "47ccb360-54d5-4aa8-8738-045758de12fa",
"wallet_address" : "0x2Ed57f25904Bc693c5bB975C23cF0176711D0b7D",
"details" : "{\"bundle_id\": \"47ccb360-54d5-4aa8-8738-045758de12fa\", \"tx_cost\": 17073173440000, \"gas_used\": 463240, \"block_number\": 310203737, \"token0_symbol\": \"PENDLE\", \"token1_symbol\": \"WETH\", \"amount0\": 883588604414007095, \"amount1\": 952908622879058, \"position_id\": 4252339, \"bound_tick_lower\": -67620, \"bound_tick_upper\": -67380, \"bound_price_lower\": 0.0011573042248154706, \"bound_price_upper\": 0.0011854140899294594, \"pool_tick\": -67505, \"pool_spot_rate\": 0.0011706968271527618}",
"agent_id" : "7446ccae-25a7-423f-a436-6f0bcca5d28e",
"user_id" : "725c4b09-a806-42b1-ab86-3e7bcc2338d4"
}
]}

Here is an example of a CLOSE_POSITION Metric (an Action, system-level metric) in the Database:

{
"metrics_action": [
{
"id" : 122,
"time" : "2025-02-26T20:29:13.094141+00:00",
"block_number" : 310208624,
"metric_type" : "CLOSE_POSITION",
"strategy_id" : "BLUECHIP_PENDLE_WETH",
"action_id" : "918f435e-b56c-4bf3-9b3d-ce2bdfbbc970",
"bundle_id" : "19e3e918-ded4-4223-aca6-cf333a47ad33",
"wallet_address" : "0x2Ed57f25904Bc693c5bB975C23cF0176711D0b7D",
"details" : "{\"bundle_id\": \"19e3e918-ded4-4223-aca6-cf333a47ad33\", \"tx_cost\": 173722516924000, \"gas_used\": 283903, \"block_number\": 310208624, \"position_id\": 4252339, \"token0_symbol\": \"PENDLE\", \"token1_symbol\": \"WETH\", \"amount0\": 1396649991039460737, \"amount1\": 356222210254997, \"liquidity0\": 1395110806879584377, \"liquidity1\": 356222210254997, \"fees0\": 1539184159876360, \"fees1\": 0, \"pool_tick\": -67577, \"pool_spot_rate\": 0.0011623017129901419}",
"agent_id" : "7446ccae-25a7-423f-a436-6f0bcca5d28e",
"user_id" : "725c4b09-a806-42b1-ab86-3e7bcc2338d4"
}
]}

In src.almanak_library.metrics.metrics_add we offer an Enum for MetricAggType we recommend using for custom Metric types related to them. But you are obviously not limited to that enum, you can create your own string. By standard use a "CAPITALIZED_METRIC_TYPE".

class MetricAggType(Enum):
INITIALIZATION = "INITIALIZATION"
TEARDOWN = "TEARDOWN"
STRATEGY_BALANCE = "STRATEGY_BALANCE"
WALLET_BALANCE = "WALLET_BALANCE"
SNAPSHOT = "SNAPSHOT"
REBALANCE_TRIGGER = "REBALANCE_TRIGGER"

You are now ready to create a beautiful Dashboard from the metrics!