|
27 | 27 | - Store per-run state on the global `g` namespace. |
28 | 28 | - Confirm decisions from visible completed data only. Never read future rows, use negative shifts, or otherwise introduce look-ahead bias. |
29 | 29 |
|
| 30 | +## Parameters and metadata |
| 31 | +- Declare tunable strategy knobs with `# @param <name> <int|float|bool|str> <default> <description>` and keep every declared default identical to the fallback used in code. |
| 32 | +- Read run-supplied values only inside executable handlers or scheduled callbacks with `context.params.get("name", same_default)`. The discovery context used by `initialize(context)` has no `params`; never read `context.params` in `initialize`. |
| 33 | +- Parameters may control signal periods, thresholds, target weights, stops, take profit, trailing protection, cooldowns, and bounded layer counts. |
| 34 | +- Do not disguise universe, symbol, market type, frequency, leverage permission, initial capital, date range, commission, or slippage as ordinary strategy parameters. |
| 35 | +- Use `context.set_metadata(...)` in `initialize` for stable descriptive metadata such as direction mode and strategy family. Metadata is not a substitute for executable risk logic. |
| 36 | +
|
30 | 37 | ## Data and factors |
31 | 38 | - Historical-bar signatures are exact: `get_history(count, frequency=None, field=None, security_list=None)` and `data.history(symbols, count, fields=None)`. |
| 39 | +- Read the current scalar field with `data.current(symbol, field="close")`. There is no `get_current_data` API and `data.current(...)` does not return an object with a `.close` attribute. |
32 | 40 | - In `get_history(...)`, `count` is always the first argument and must be an integer. In `data.history(...)`, symbols are first and the integer count is second. Prefer explicit keywords when using `data.history`, for example `data.history(symbol, count=60, fields=["close"])`. |
33 | 41 | - A history request for one symbol returns a pandas `DataFrame` directly. Use `bars["close"]`; never index the result again with `bars[symbol]`. Multiple-symbol requests return a dictionary keyed by canonical symbol. |
34 | 42 | - Use `indicator(name, symbol, **params)`, `factor(name, symbol, **params)`, or `get_factors(symbols, names, **params)` for technical factors. |
|
41 | 49 | - Order-helper signatures are exact: `order(symbol, amount)`, `order_value(symbol, value)`, `order_target(symbol, amount)`, `order_target_value(symbol, value)`, and `order_target_percent(symbol, percent)`. |
42 | 50 | - These are runtime-bound global helpers. Never pass `context` as their first argument. Optional execution and protection values must be keyword arguments after the two required arguments. |
43 | 51 | - `get_position(symbol)` returns a `Position` object. Read `position.amount`, `position.avg_cost`, and `position.last_price` directly; never use dictionary membership, subscripting, `.get(...)`, or `getattr(...)` on it. |
| 52 | +- A `Position` has no `.quantity` or `.cost_basis`; use `.amount` and `.avg_cost`. |
44 | 53 | - Use `get_positions(...)` when a dictionary of multiple positions is required. |
45 | 54 | - Values passed to value-based order APIs are quote-currency exposure targets. Keep sizing bounded by available capital and explicit allocation rules. |
46 | 55 | - Keep long entry, long exit, short entry, and short exit conditions independent. A bearish long exit is not automatically a short entry. |
|
72 | 81 | - Require a metadata docstring and `initialize(context)`. |
73 | 82 | - Require a source-owned universe and subscription. |
74 | 83 | - Require at least one executable handler or registered schedule callback. |
| 84 | +- Declare tunable knobs with `# @param` and read them with matching `context.params.get(...)` fallbacks only inside executable handlers or callbacks. Never read `context.params` in `initialize`. |
| 85 | +- Do not expose universe, symbol, market type, frequency, leverage permission, initial capital, date range, commission, or slippage as ordinary strategy parameters. |
75 | 86 | - Use only Strategy API V2 data, factor, fundamental, position, and order APIs. |
76 | 87 | - Prefer `handle_data(context, data)` for single-symbol signal strategies. Use schedules only for an explicitly requested schedule or periodic portfolio rebalance. |
77 | 88 | - Schedule helpers are global calls: `run_daily(callback, time="HH:MM")`, `run_weekly(callback, weekday=1, time="HH:MM")`, and `run_monthly(callback, monthday=1, time="HH:MM")`. Never call them through `context`. |
78 | 89 | - Enforce exact history signatures: `get_history(count, frequency, field, security_list)` and `data.history(symbols, count, fields)`. A single-symbol result is already a DataFrame. |
| 90 | +- Use `data.current(symbol, field="close")` for a current scalar field. Replace every `get_current_data` call; that API does not exist. |
79 | 91 | - Enforce exact order signatures such as `order_target_percent(symbol, percent)` and never pass `context` to a global order helper. |
80 | 92 | - Treat `get_position(symbol)` as a `Position` object with direct `.amount`, `.avg_cost`, and `.last_price` attributes. Never treat it as a dictionary or use `getattr`. |
| 93 | +- Replace legacy `.quantity` and `.cost_basis` position access with `.amount` and `.avg_cost`. |
81 | 94 | - Preserve completed-data-only execution and remove look-ahead. |
82 | 95 | - Keep symbol, market, frequency, schedule, and universe in source code. |
83 | 96 | - Permit user-adjustable leverage only for Crypto `@swap` instruments and only after `context.allow_leverage(max_leverage=N)`. |
|
0 commit comments