Strategies¶
fundcloud.strategies exposes the abstract BaseStrategy together with two preset implementations (Hold, DCA), a per-bar Context object, and the Cadence / Scheduler primitives that govern when a strategy fires. The @register_strategy decorator participates in Catalog serialisation so a strategy name round-trips through YAML configs. For usage patterns and the custom-strategy worked example, see the DCA & Hold guide.
fundcloud.strategies
¶
Decision-logic presets and extension points.
Two built-in presets (:class:Hold and :class:DCA) cover the common
retail / allocation workflows. Custom strategies subclass
:class:BaseStrategy and may optionally register themselves via
:func:register_strategy so they become discoverable by name.
BaseStrategy
¶
Context
dataclass
¶
Context(
ts: Timestamp,
bar: Series,
history: DataFrame,
portfolio: Portfolio,
assets: tuple[str, ...],
extras: Mapping[str, Any] = dict(),
)
Per-bar context handed to :meth:BaseStrategy.decide.
Attributes:
| Name | Type | Description |
|---|---|---|
ts |
Timestamp
|
Current bar timestamp. |
bar |
Series
|
Current bar. For a |
history |
DataFrame
|
Bars up to and including |
portfolio |
Portfolio
|
Live :class: |
assets |
tuple[str, ...]
|
Convenience: asset universe ordered by column appearance. |
extras |
Mapping[str, Any]
|
Optional dict for user-specified scheduled events, factor scores, etc. Populated by the simulator if needed, else an empty dict. |
Hold
¶
Hold(
weights: WeightsLike,
*,
rebalance: RebalanceSpec | None = None,
start: Timestamp | str | None = None,
)
Bases: BaseStrategy
Allocate to target weights once, hold; optionally rebalance.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
weights
|
WeightsLike
|
Either a mapping of |
required |
rebalance
|
RebalanceSpec | None
|
If supplied, restore target weights at each cadence boundary. |
None
|
start
|
Timestamp | str | None
|
Optional lock-out: don't place the first allocation before |
None
|
Examples:
Buy-and-hold 60/40 equity / bonds, no rebalancing (weights drift with prices):
>>> from fundcloud.strategies import Hold
>>> Hold({"SPY": 0.6, "AGG": 0.4})
<fundcloud.strategies.hold.Hold object at ...>
Quarterly-rebalanced 60/40 with a 5 %-drift tolerance:
>>> from fundcloud.strategies import RebalanceSpec
>>> Hold(
... {"SPY": 0.6, "AGG": 0.4},
... rebalance=RebalanceSpec(horizon="91D", tolerance=0.05),
... )
<fundcloud.strategies.hold.Hold object at ...>
Source code in python/fundcloud/strategies/hold.py
RebalanceSpec
dataclass
¶
Optional rebalance policy for :class:Hold.
DCA
¶
DCA(
amount: float | Mapping[str, float],
*,
horizon: HorizonName | Cadence | str = "monthly",
weights: Mapping[str, float] | None = None,
start: Timestamp | str | None = None,
end: Timestamp | str | None = None,
sell_on_end: bool = False,
)
Bases: BaseStrategy
Invest a fixed amount at a fixed cadence.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
amount
|
float | Mapping[str, float]
|
Either a scalar (distributed across |
required |
horizon
|
HorizonName | Cadence | str
|
Cadence — |
'monthly'
|
weights
|
Mapping[str, float] | None
|
Optional. When omitted with a scalar |
None
|
start
|
Timestamp | str | None
|
Optional window inside which DCA fires. |
None
|
end
|
Timestamp | str | None
|
Optional window inside which DCA fires. |
None
|
sell_on_end
|
bool
|
When |
False
|
Examples:
Single-asset weekly DCA into SPY — the classic retail deposit:
>>> from fundcloud.strategies import DCA
>>> DCA(amount=500.0, horizon="weekly", weights={"SPY": 1.0})
<fundcloud.strategies.dca.DCA object at ...>
Multi-asset monthly allocation with explicit dollar buckets per leg:
>>> DCA({"SPY": 300.0, "AGG": 200.0}, horizon="monthly")
<fundcloud.strategies.dca.DCA object at ...>
Scalar amount with no weights — equal-weight over whatever assets the bars frame contains:
Source code in python/fundcloud/strategies/dca.py
Scheduler
¶
Factory for :class:Cadence presets.
from_horizon
staticmethod
¶
from_horizon(
horizon: HorizonName | Cadence | str,
*,
anchor: Timestamp | None = None,
) -> Cadence
Resolve a user-facing horizon into a concrete :class:Cadence.
Accepted forms:
"daily"→ every trading day (1Dstep anchored atanchor)."weekly"→ every 7 calendar days fromanchor(not ISO weekday 1 — matches PRD's "(7 days)" wording)."monthly"→ same day-of-month asanchoreach month, falling back to the last trading day of the month if missing.- a :class:
Cadenceis returned as-is (withanchormerged in). - any pandas offset string (e.g.
"30D","3W") → :class:Cadence.
Source code in python/fundcloud/strategies/scheduler.py
Cadence
dataclass
¶
An explicit cadence step. Use :meth:Scheduler.from_horizon for presets.
step is any pandas-parseable offset like "7D", "14D", or
"1D". Anchor is the first timestamp the cadence fires on; if
unspecified the first trigger falls on the first timestamp in the passed
index.
triggers
¶
triggers(
index: DatetimeIndex,
*,
start: Timestamp | str | None = None,
end: Timestamp | str | None = None,
) -> pd.DatetimeIndex
Return the subset of index that the cadence fires on.
Source code in python/fundcloud/strategies/scheduler.py
register_strategy
¶
Decorator: make a strategy class discoverable by name.