# DCA vs Lump-Sum

A side-by-side **monthly running comparison** of two contribution strategies on the same total budget:

* **DCA (Dollar-Cost Averaging)** — invest a fixed `$1000` at the start of each month, accumulating BTC at whatever the price is that month.
* **Lump-sum** — at month `T`, this represents "what if I had instead invested all `T × $1000` at month 0's price?". Useful as a baseline to read off DCA's smoothing-vs-opportunity-cost trade-off at a glance. 12-31`to match the parity-tested baseline; for live data swap the two date literals for a relative window like`now() - interval 5 year\`.

Three SQL details worth flagging:

## Query

```sql
WITH
    '2020-01-01' AS start_date,
    '2024-12-31' AS end_date,
    1000 AS monthly_contribution,
    monthly AS (
        SELECT toStartOfMonth(toDate(start)) AS month,
               argMin(toFloat64(close), start) AS open_price
        FROM api.ohlcv(candle_duration_in_minutes = 1440)
        WHERE exchange = 'binance'
          AND market = 'BTC-USDT'
          AND start BETWEEN start_date AND end_date
        GROUP BY month
    )
SELECT month,
       open_price,
       sum(monthly_contribution) OVER w AS cumulative_invested,
       sum(monthly_contribution / open_price) OVER w AS dca_btc,
       sum(monthly_contribution / open_price) OVER w * open_price AS dca_portfolio_value,
       sum(monthly_contribution) OVER w / first_value(open_price) OVER w AS lumpsum_btc,
       sum(monthly_contribution) OVER w / first_value(open_price) OVER w * open_price AS lumpsum_portfolio_value
FROM monthly
WINDOW w AS (ORDER BY month)
ORDER BY month
```

Three SQL details worth flagging:

* **Monthly bucket via `toStartOfMonth(toDate(start))`** + `argMin(close, start)` picks the first daily close in each calendar month — same as `groupby('month').first()` in pandas. We **buy and value at the same monthly open price**, so the latest month's row honestly shows zero return on its just-purchased contribution; earlier rows reflect the appreciation since that month.
* **DCA accumulates** via `sum(monthly_contribution / open_price) OVER w` — one running sum, not a manual loop. Multiply by the current month's open to mark-to-market.
* **Lump-sum** is anchored to month 0's price via `first_value(open_price) OVER w`. At every row, `cumulative_invested / first_open_price` gives the BTC count you'd hold if you'd put the whole running total in at the start.

## Output (2020 — 2024, 60 monthly rows)

First and last few:

| month      | open\_price | cumulative\_invested | dca\_btc | dca\_portfolio\_value | lumpsum\_btc | lumpsum\_portfolio\_value |
| ---------- | ----------- | -------------------- | -------- | --------------------- | ------------ | ------------------------- |
| 2020-01-01 | 7200.85     | 1,000                | 0.14     | 1,000.00              | 0.14         | 1,000.00                  |
| 2020-02-01 | 9384.61     | 2,000                | 0.25     | 2,303.26              | 0.28         | 2,606.53                  |
| 2020-03-01 | 8531.88     | 3,000                | 0.36     | 3,093.98              | 0.42         | 3,554.53                  |
| ...        | ...         | ...                  | ...      | ...                   | ...          | ...                       |
| 2024-10-01 | 60805.78    | 58,000               | 2.57     | 156,432.34            | 8.05         | 489,766.52                |
| 2024-11-01 | 69496.01    | 59,000               | 2.59     | 179,789.31            | 8.19         | 569,413.97                |
| 2024-12-01 | 97185.18    | 60,000               | 2.60     | 252,422.44            | 8.33         | 809,780.90                |

After 60 months on `BTC-USDT`:

|              | Final BTC | Final value | Return on $60k |
| ------------ | --------- | ----------- | -------------- |
| **DCA**      | 2.60      | $ 252,422   | +320.7 %       |
| **Lump-sum** | 8.33      | $ 809,781   | +1,249.6 %     |

## Extending it

* **Different cadence** — change `toStartOfMonth(...)` to `toStartOfWeek(...)` for weekly DCA, or `toStartOfQuarter(...)` for quarterly. The contribution amount adjusts to match.
* **Different basket** — the SQL pattern is single-asset; for a multi-asset DCA wrap the inner CTE with a `PARTITION BY market` on every window function and add `market` to the final `ORDER BY`.
* **Variable contributions** — replace the constant `1000 AS monthly_contribution` with a join against a table or values list of `(month, contribution)` to model irregular schedules.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.koinju.io/compute-engine/dca-vs-lump-sum.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
