Framework vs User Control¶
This document is the canonical strategy contract for StackSats.
Framework (Non-Negotiable)¶
- Given a fixed budget: generalized to a proportion (total accumulation weight = 1).
- Given a fixed allocation span (global config) between 90 and 1460 days (inclusive).
- Defines a complete strategy that:
- Initializes all daily accumulation weights over the allocation span such that the sum of all weights equals the total budget (=1).
- Makes day-by-day iterative updates to future weights, reshuffling the fixed budget.
- Locks historical weights (past days are immutable).
- Enforced budget management:
- Total budget must be used by the end of the allocation span (meaning all daily weights must sum to 1).
- Enforced daily accumulation:
- Minimum daily weight must be greater than or equal to
1e-5. - Enforced steady accumulation:
- Maximum daily weight must be less than or equal to
0.1. - No Forward-Looking Data:
- Use only current and past data—no peeking into the future.
- Validation guards (
NaN/inf/range checks) and final invariants.
WeightTimeSeries is the output object that enforces these invariants: required columns (date, weight, price_usd), weight sum = 1, non-negative and finite weights, daily weight within min/max bounds, date contract, and optional locked/day_index. Input features are provided as FeatureTimeSeries (schema and time-series validation, including optional no-forward-looking checks).
User Owns (Flexible)¶
- Feature engineering from lagged/base data
- Signal definitions/formulas
- Signal weights and hyperparameters
- Stable strategy identity/config surfaced through
metadata(),params(), andspec() - Daily intent output:
propose_weight(state)for per-day proposals, orbuild_target_profile(...)for a full-window intent series
When both intent hooks are implemented, intent_preference must be set explicitly.
Ambiguous dual-hook strategies are rejected by contract validation.
Handoff Boundary¶
The user never writes the framework iteration loop.
User output (proposed_weight_today or daily profile intent) is handed to the framework allocation kernel, which computes final_weight_today by applying:
- feasibility clipping
- remaining-budget rules
- historical lock rules
- final invariant checks
Required Behavior¶
- Users can strongly influence allocation each day through features/signals/intent.
- Users cannot alter iteration mechanics or rewrite past allocations.
- Local, backtest, decision, and production-integrated execution run the same sealed allocation kernel.
- Hard-required transformed columns should be declared via
required_feature_columns(). - Durable strategy configuration should come from
params(), not runtime caches.
Production Daily Lifecycle¶
Canonical agent-native entrypoint: stacksats strategy decide-daily.
Hosted agent-native surface: stacksats serve agent-api.
- Load locked historical weights for the active allocation span.
- Build lagged features/signals using information available up to
current_date. - Collect user daily intent (
proposed_weight_todayor profile-derived intent). - Project to feasible
final_weight_todaywith remaining-budget constraints. - Emit a structured decision payload for an external agent.
- Either hand that payload to an external agent directly or serve it over the hosted
/v1/decisions/dailyHTTP surface. - External brokerage execution happens outside StackSats.
- External agents report execution receipts back through
/v1/executions/receiptswhen using the hosted service. - Persist today as locked.
- Advance to next day; past values remain immutable.
Integrated convenience path: stacksats strategy run-daily.
Use it when you intentionally want StackSats to submit through an execution adapter after generating the same validated decision.