Skip to content
Finance
Skill

/dca-weekly

Use when writing, validating, or troubleshooting a recurring scheduled buy strategy (DCA, dollar-cost averaging, weekly buys, daily buys, monthly accumulation, accumulator) on Superior Trade — especially anything that should "buy more of the same pair" on a calendar trigger

BOOST
From plugin
superior-skills
21630 skills
Install
$ npx -y skills add Superior-Trade/superior-skills --skill dca-weekly --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/dca-weekly

Context preview

The summary Claude sees to decide when to auto-load this skill.

Use when writing, validating, or troubleshooting a recurring scheduled buy strategy (DCA, dollar-cost averaging, weekly buys, daily buys, monthly accumulation, accumulator) on Superior Trade — especially anything that should "buy more of the same pair" on a calendar trigger

SKILL.md

dca-weekly.SKILL.md
name: dca-weekly
description: Use when writing, validating, or troubleshooting a recurring scheduled buy strategy (DCA, dollar-cost averaging, weekly buys, daily buys, monthly accumulation, accumulator) on Superior Trade — especially anything that should "buy more of the same pair" on a calendar trigger rather than a price trigger.
metadata:
  version: 0.1.0
  updated: 2026-05-07

Strategy: DCA · Scheduled Buys

When to use

A user asks to "buy X every week", "DCA into BTC", "scheduled buy", "accumulator", "monthly buy", or any variation that means *open a position once, then keep adding to it on a calendar cadence*. **Not** for "buy when price drops" — that's grid trading (see `grid-trading`).

What it does

  • Holds **one open trade per pair** (Freqtrade's hard rule).
  • The first calendar trigger opens the trade with a **small** initial stake.
  • Every subsequent trigger calls `adjust_trade_position` and adds the **same notional** to the open trade.
  • The position grows in fills inside a single Trade row. PnL is reported per-trade.
  • Exits only when the user sets one (typically never, for true DCA — `stoploss = -0.99` and no `populate_exit_trend`).

Backtest reference

| Window | `BTC/USDC` 1d, 2025-11-15 → 2026-05-01 (auto-narrowed to data availability, ~10 weeks) | |---|---| | Trades | 1 (still open at end, force-closed) | | Entry orders inside the trade | **10** (1 initial + 9 weekly DCA, tagged `weekly_dca`) | | Stake per buy | ~$36.87 | | Total invested | ~$365 of $10,000 wallet | | Per-trade PnL | +10.0% | | Wallet PnL | +0.37% / +$36.61 | | Holding | 66 days | | Backtest ID | `01kqyz1ysdy9dyw7tbdrhz5gek` |

The `(rejected_signals: 9)` warning in logs is normal: `populate_entry_trend` keeps emitting Monday flags even while a trade is open, but `adjust_trade_position` does the actual buys.

The Freqtrade primitives that make this work

These four flags are the difference between v1 (1 trade ever, the rest rejected) and v2 (a real ladder of fills). All four are required:

position_adjustment_enable = True
max_entry_position_adjustment = 26   # cap on number of weekly adds
max_dca_multiplier = 27.0            # 1 initial + 26 adds

Plus two callbacks:

  • `custom_stake_amount` — divides the user-configured stake by `max_dca_multiplier` so the **initial** entry leaves room for the future weekly adds.
  • `adjust_trade_position` — the calendar trigger. Returns `(stake, tag)` to add, `None` to do nothing.

Reference implementation

from freqtrade.strategy import IStrategy
from freqtrade.persistence import Trade
from datetime import datetime
import pandas as pd


class WeeklyDcaBtcStrategy(IStrategy):
    minimal_roi = {"0": 100.0}   # never exit on profit target
    stoploss = -0.99             # never exit on stop
    trailing_stop = False
    timeframe = "1d"
    process_only_new_candles = True
    startup_candle_count = 5
    can_short = False

    # The piece naive translations miss.
    position_adjustment_enable = True
    max_entry_position_adjustment = 26   # ~6 months of weekly buys
    max_dca_multiplier = 27.0            # 1 initial + 26 weekly adds

    def populate_indicators(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame:
        dataframe["dow"] = pd.to_datetime(dataframe["date"]).dt.dayofweek
        return dataframe

    def populate_entry_trend(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame:
        # Initial entry on the first Monday encountered.
        dataframe.loc[(dataframe["dow"] == 0) & (dataframe["volume"] > 0), "enter_long"] = 1
        return dataframe

    def populate_exit_trend(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame:
        return dataframe

    def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float,
                            proposed_stake: float, min_stake, max_stake: float,
                            leverage: float, entry_tag, side: str, **kwargs) -> float:
        # Reserve room for the future weekly adds.
        return proposed_stake / self.max_dca_multiplier

    def adjust_trade_position(self, trade: Trade, current_time: datetime,
                              current_rate: float, current_profit: float,
                              min_stake, max_stake: float,
                              current_entry_rate: float, current_exit_rate: float,
                              current_entry_profit: float, current_exit_profit: float,
                              **kwargs):
        if trade.has_open_orders:
            return None
        if current_time.weekday() != 0:   # Monday only
            return None
        # Skip the Monday on which the initial entry was placed (Freqtrade
        # calls adjust_trade_position on the same candle as the initial
        # entry; without this guard you double-buy on week 1).
        filled = trade.select_filled_orders(trade.entry_side)
        if filled:
            last_dt = filled[-1].order_filled_utc
            if last_dt and last_dt.date() == current_time.date():
                return None
        # Buy the same notional as the initial entry every Monday.
        first_stake = filled[0].stake_amount_filled if filled else (min_stake or 10)
        return (first_stake, "weekly_dca")

Config requirements

{
  "exchange": { "name": "hyperliquid", "pair_whitelist": ["BTC/USDC"] },
  "stake_currency": "USDC",
  "stake_amount": 1000,
  "dry_run_wallet": {"USDC": 10000},
  "timeframe": "1d",
  "max_open_trades": 1,
  "stoploss": -0.99,
  "minimal_roi": { "0": 100.0 },
  "entry_pricing": { "price_side": "same" },
  "exit_pricing": { "price_side": "same" },
  "pairlists": [{ "method": "StaticPairList" }]
}

`stake_amount` is the **post-division** budget the user wants per buy times `max_dca_multiplier`. With `stake_amount: 1000` and `max_dca_multiplier: 27`, each Monday buy is ~$37; total budget is ~$1000.

`dry_run_wallet` must be ≥ `stake_amount` (Freqtrade keeps

Read more
Ships withsuperior-skills

Trading strategies and intelligence tools for Superior Trade — natural-language strategy authoring, backtesting, and autonomous deployment on Hyperliquid, Lighter, and Polymarket.

Get the whole plugin
Stats
216
Stars
9
Forks
Maintained
Maintenance
JavaScript
Language
MIT
License
1mo ago
Last commit
7mo ago
Created
20m ago
Added

Repo: Superior-Trade/superior-skills

Other skills on superior-skills.