Skip to main content

Strategy

No description

type Strategy implements Node {
aiHistory(
first: Int
): [AIHistoryEntry!]!
backtestStats: BacktestStats
runningBacktestCount: Int!
versionChainBacktestCount: Int!
analysis: StrategyAnalysis
encryptionStatus: EncryptionStatus!
id: ID!
public: Boolean!
featured: Boolean!
deletedAt: Time
encryptionMode: StrategyEncryptionMode!
keyCustodyBackend: StrategyKeyCustodyBackend!
keyID: String
keyVersion: Int
algorithm: StrategyEncryptionAlgorithm!
encryptedAt: Time
name: String!
description: String
code: String
config: Map!
authoredBy: StrategyStrategyCodeAuthor!
builderMode: StrategyStrategyBuilderMode!
tradingMode: StrategyStrategyTradingMode!
timeframe: String!
stakeCurrency: String!
positionMode: StrategyStrategyPositionMode!
parentID: ID
forkedFromID: ID
originListingID: ID
originOwnerID: String
isLatest: Boolean!
versionNumber: Int!
ownerID: String!
createdAt: Time!
updatedAt: Time!
bots(
after: Cursor
first: Int
before: Cursor
last: Int
orderBy: [BotOrder!]
where: BotWhereInput
): BotConnection!
backtests(
after: Cursor
first: Int
before: Cursor
last: Int
orderBy: [BacktestOrder!]
where: BacktestWhereInput
): BacktestConnection!
simulations(
after: Cursor
first: Int
before: Cursor
last: Int
orderBy: [SimulationOrder!]
where: SimulationWhereInput
): SimulationConnection!
hyperopts(
after: Cursor
first: Int
before: Cursor
last: Int
orderBy: [HyperoptOrder!]
where: HyperoptWhereInput
): HyperoptConnection!
children: [Strategy!]
parent: Strategy
forkedFrom: Strategy
forks: [Strategy!]
biasClearance: BiasClearance!
biasReport: BiasCheckReport
usesFreqai: Boolean!
encryptionLocked: Boolean!
effectiveTradingMode: StrategyStrategyTradingMode!
uiBuilderConfig: UIBuilderConfig
latestVerdict: StrategyVerdict
wrappedDEKs: [WrappedDEK!]!
}

Fields​

Strategy.aiHistory ● [AIHistoryEntry!]! non-null object​

What the assistant changed on this strategy, across all its versions, newest first.

Strategy.aiHistory.first ● Int scalar​

Strategy.backtestStats ● BacktestStats object​

Aggregated backtest statistics for this strategy version. Provides best, worst, latest, and average metrics for easy comparison.

Strategy.runningBacktestCount ● Int! non-null scalar​

Number of backtests in {running, pending} status for this strategy version. Server-derived at query time. Updates pushed via the strategyBacktestActivity subscription whenever a backtest crosses the active-set boundary — Apollo's normalized cache (Strategy:<id>) picks them up automatically, no client refetch / poll / debounce.

See docs/superpowers/specs/2026-05-13-strategy-running-backtest-count-design.md

Strategy.versionChainBacktestCount ● Int! non-null scalar​

How many backtests exist across EVERY version of this strategy's version chain — not just this row's own (#2753).

WHY IT EXISTS: backtests(first: 1) { totalCount } is row-scoped, so a version the user has just saved honestly reports zero and the strategies-list card looked like the whole backtest history had been lost. The detail page's Versions table asks the chain's question and kept showing every run, so the two surfaces contradicted each other about the same fact.

It cannot be assembled client-side: a per-row chain query on a paginated list is N round trips, and N aliased connections in one document trip the complexity limit.

Chain identity is (name, owning workspace) — the platform's own definition, the one strategyVersions(name:) uses. Counts every status, exactly as the connection totalCount it replaces did.

NO OWN DIRECTIVE, like backtestStats and digest: parent-node access already gates reaching it, and the chain members are scoped to what the caller could have listed (the owner-or-public predicate tenancy.ScopeBacktests itself applies). A public version's runs therefore count for a stranger reading the marketplace, and a private sibling's do not.

Strategy.analysis ● StrategyAnalysis object​

Cached analysis blob. Returns Unavailable when not yet computed (resolver lazy-fills).

Strategy.encryptionStatus ● EncryptionStatus! non-null object​

Strategy.id ● ID! non-null scalar​

Strategy.public ● Boolean! non-null scalar​

Whether this resource is publicly visible to all authenticated users

Whether this resource is featured (appears at top of lists)

Strategy.deletedAt ● Time scalar​

Soft-delete timestamp. If set, record is considered deleted.

Strategy.encryptionMode ● StrategyEncryptionMode! non-null enum​

Trust-ladder encryption mode for this row's sensitive fields. Set at create time; immutable after. Defaults to 'legacy_server' for all rows created before the trust ladder shipped.

Strategy.keyCustodyBackend ● StrategyKeyCustodyBackend! non-null enum​

KeyCustodyBackend implementation that produced the wrapping key. Pinned at write time alongside encryption_mode.

Strategy.keyID ● String scalar​

Opaque identifier of the wrapping key, backend-specific. Null for legacy_server rows that use the global process key.

Strategy.keyVersion ● Int scalar​

Rotation counter for the wrapping key. Null for legacy_server rows; populated when the row is rewrapped under a versioned key.

Strategy.algorithm ● StrategyEncryptionAlgorithm! non-null enum​

Symmetric algorithm protecting the row's sensitive fields. Stored alongside the ciphertext so future migrations can retire algorithms without re-encrypting existing rows.

Strategy.encryptedAt ● Time scalar​

Timestamp the row's sensitive fields were last encrypted with the current key_id/key_version. Null for legacy_server rows.

Strategy.name ● String! non-null scalar​

Strategy name (not unique, allows versions)

Strategy.description ● String scalar​

Strategy description

Strategy.code ● String scalar​

Python strategy code (server-derived for ui builder_mode; required for code mode — enforced in the strategy domain, see ADR-0088)

Strategy.config ● Map! non-null scalar​

Strategy-specific configuration (config.json) - REQUIRED

Strategy.authoredBy ● StrategyStrategyCodeAuthor! non-null enum​

Who wrote this version's code: user, or assistant (the assistant's code-edit card). Assistant code must pass a bias check before it is applied or judged.

Strategy.builderMode ● StrategyStrategyBuilderMode! non-null enum​

Strategy editing mode: 'ui' for UI builder (code generated from config), 'code' for direct Python editing

Strategy.tradingMode ● StrategyStrategyTradingMode! non-null enum​

Mirrored from config.trading_mode — normalized uppercase so it can be filtered/indexed

Strategy.timeframe ● String! non-null scalar​

Freqtrade timeframe (e.g. '5m', '1h'), default '5m'. Written THROUGH to config.timeframe, the source of truth; a conflict is rejected.

Strategy.stakeCurrency ● String! non-null scalar​

Mirrored from config.stake_currency (e.g. 'USDT', 'BTC') — default 'USDT'

Strategy.positionMode ● StrategyStrategyPositionMode! non-null enum​

Mirrored from ui_builder_config.position_mode for UI strategies; defaults LONG_AND_SHORT for code strategies

Strategy.parentID ● ID scalar​

Parent strategy ID for versioning (null for root v1)

Strategy.forkedFromID ● ID scalar​

Original strategy ID this was forked from (null if not forked)

Strategy.originListingID ● ID scalar​

Marketplace listing whose content this version still carries unedited by a person (null once a person edits it)

Strategy.originOwnerID ● String scalar​

Owner of another organization whose content this version still carries unedited by a person (null once a person edits it)

Strategy.isLatest ● Boolean! non-null scalar​

Indicates if this is the latest version of the strategy

Strategy.versionNumber ● Int! non-null scalar​

Auto-incremented version number

Strategy.ownerID ● String! non-null scalar​

Group ID (organization) that owns this strategy

Strategy.createdAt ● Time! non-null scalar​

Strategy.updatedAt ● Time! non-null scalar​

Strategy.bots ● BotConnection! non-null object​

Strategy.bots.after ● Cursor scalar​

Returns the elements in the list that come after the specified cursor.

Strategy.bots.first ● Int scalar​

Returns the first _n_ elements from the list.

Strategy.bots.before ● Cursor scalar​

Returns the elements in the list that come before the specified cursor.

Strategy.bots.last ● Int scalar​

Returns the last _n_ elements from the list.

Strategy.bots.orderBy ● [BotOrder!] list input​

Ordering options for Bots returned from the connection.

Strategy.bots.where ● BotWhereInput input​

Filtering options for Bots returned from the connection.

Strategy.backtests ● BacktestConnection! non-null object​

Strategy.backtests.after ● Cursor scalar​

Returns the elements in the list that come after the specified cursor.

Strategy.backtests.first ● Int scalar​

Returns the first _n_ elements from the list.

Strategy.backtests.before ● Cursor scalar​

Returns the elements in the list that come before the specified cursor.

Strategy.backtests.last ● Int scalar​

Returns the last _n_ elements from the list.

Strategy.backtests.orderBy ● [BacktestOrder!] list input​

Ordering options for Backtests returned from the connection.

Strategy.backtests.where ● BacktestWhereInput input​

Filtering options for Backtests returned from the connection.

Strategy.simulations ● SimulationConnection! non-null object​

Strategy.simulations.after ● Cursor scalar​

Returns the elements in the list that come after the specified cursor.

Strategy.simulations.first ● Int scalar​

Returns the first _n_ elements from the list.

Strategy.simulations.before ● Cursor scalar​

Returns the elements in the list that come before the specified cursor.

Strategy.simulations.last ● Int scalar​

Returns the last _n_ elements from the list.

Strategy.simulations.orderBy ● [SimulationOrder!] list input​

Ordering options for Simulations returned from the connection.

Strategy.simulations.where ● SimulationWhereInput input​

Filtering options for Simulations returned from the connection.

Strategy.hyperopts ● HyperoptConnection! non-null object​

Strategy.hyperopts.after ● Cursor scalar​

Returns the elements in the list that come after the specified cursor.

Strategy.hyperopts.first ● Int scalar​

Returns the first _n_ elements from the list.

Strategy.hyperopts.before ● Cursor scalar​

Returns the elements in the list that come before the specified cursor.

Strategy.hyperopts.last ● Int scalar​

Returns the last _n_ elements from the list.

Strategy.hyperopts.orderBy ● [HyperoptOrder!] list input​

Ordering options for Hyperopts returned from the connection.

Strategy.hyperopts.where ● HyperoptWhereInput input​

Filtering options for Hyperopts returned from the connection.

Strategy.children ● [Strategy!] list object​

Child strategy versions derived from this strategy (self-referential, via parent_id)

Strategy.parent ● Strategy object​

Strategy.forkedFrom ● Strategy object​

Original strategy this was forked from

Strategy.forks ● [Strategy!] list object​

Strategies forked from this one

Strategy.biasClearance ● BiasClearance! non-null enum​

Whether this version's code may be judged and applied, as far as bias goes (T-P4-IM-02).

Strategy.biasReport ● BiasCheckReport object​

The conclusive bias check the clearance rests on, when there is one.

Strategy.usesFreqai ● Boolean! non-null scalar​

Whether the strategy config uses FreqAI (a freqaimodel or freqai block). Server-derived from the config the caller's read decrypted; false when the config is passphrase-sealed and the session cannot open it.

Strategy.encryptionLocked ● Boolean! non-null scalar​

True when the strategy has at least one passphrase-encrypted IP field (code / config / ui_builder_config / analysis) that the current session could not decrypt. Editors must surface an unlock prompt and refuse Save while this is true.

Strategy.effectiveTradingMode ● StrategyStrategyTradingMode! non-null enum​

The market this strategy actually runs on: the stored Freqtrade config.trading_mode when it declares one, otherwise the mirrored tradingMode column (which carries a UI-builder strategy's mode). Same resolution the backtest and hyperopt spec builders apply, so this is the market the container will be dispatched on.

Read THIS to decide anything market-dependent — pair scope, stake currencies, readiness, the mode chip. Do not re-derive it from config, and prefer it over tradingMode, which is a SQL-filterable mirror and can lag the config.

Never null: a strategy that declares no mode anywhere runs on Freqtrade's own default for an absent trading_mode, which is SPOT.

Strategy.uiBuilderConfig ● UIBuilderConfig object​

UI builder configuration — only present for builder_mode='ui' strategies

Strategy.latestVerdict ● StrategyVerdict object​

The most recent D6 verdict for this version, or null when it was never evaluated.

Strategy.wrappedDEKs ● [WrappedDEK!]! non-null object​

All envelopes wrapping the strategy's DEK to a passkey public key. Populated only when the strategy is encrypted under T2.2; empty list means the strategy is either plaintext or encrypted under an earlier trust tier (T1.1 passphrase, T1.4 strict mode).

Authorization piggybacks on the parent Strategy.@hasScope check — this list is opaque ciphertext, but exposing it across orgs would reveal who has access, so we restrict to the resource's own view-scope holders.

Interfaces​

Node interface​

An object with an ID. Follows the Relay Global Object Identification Specification

Returned By​

applyHyperoptParamsToStrategy mutation ● applyStrategyVersion mutation ● convertStrategyToBuilder mutation ● convertStrategyToCode mutation ● createStrategy mutation ● createStrategyWithPassphrase mutation ● decryptStrategyOnce mutation ● forkFromListing mutation ● forkStrategy mutation ● renameStrategy mutation ● restoreStrategyVersion mutation ● setStrategyFeatured mutation ● setStrategyUIBuilderEncrypted mutation ● setStrategyVisibility mutation ● strategy query ● strategyBacktestActivity subscription ● strategyVersions query ● updateStrategy mutation ● updateStrategyCodeWithPassphrase mutation ● updateStrategyWithPassphrase mutation

Member Of​

Backtest object ● Bot object ● Hyperopt object ● Simulation object ● Strategy object ● StrategyChangeProposal object ● StrategyCodeChangeProposal object ● StrategyEdge object