Position Management
Position management is how Botmarley tracks your open trades, controls how many positions can be open at once, and handles adding to or exiting positions. Good position management is often the difference between a profitable strategy and a losing one.
What Is a Position?
A position is an active trade. When a strategy's open_long action fires, Botmarley creates a new position that tracks:
| Field | Description |
|---|---|
| Entry price | The price at which the position was opened |
| Quantity | How much of the asset was bought |
| Total cost | The total USDC (or other currency) spent |
| Current P&L | The unrealized profit or loss based on current price |
| Open time | When the position was created |
A position remains open until a sell action with amount = "100%" fires, or until all of the position has been sold through partial sells.
flowchart LR
A["open_long<br/>Creates Position"] --> B["Position Open<br/>Tracking P&L"]
B --> C["buy (DCA)<br/>Adds to Position"]
C --> B
B --> D["sell 50%<br/>Partial Exit"]
D --> B
B --> E["sell 100%<br/>Full Exit"]
E --> F["Position Closed"]
style A fill:#22c55e,color:#fff
style E fill:#ef4444,color:#fff
style F fill:#6b7280,color:#fff
max_open_positions
The max_open_positions field in the [meta] section controls how many positions can be open simultaneously. This is your primary tool for controlling capital exposure.
How It Works
[meta]
name = "Conservative Strategy"
max_open_positions = 1
| Setting | Behavior |
|---|---|
max_open_positions = 1 | Only one position at a time. New open_long triggers are ignored until the current position is fully closed. |
max_open_positions = 3 | Up to three positions can be open simultaneously. The fourth open_long trigger is ignored. |
| Omitted (no setting) | Unlimited positions. Every open_long trigger opens a new position. |
Running with unlimited positions (no max_open_positions) can be dangerous. In a sharp market downturn, the bot could open many positions rapidly, using up all available capital. Always set a limit unless you have a specific reason not to.
Choosing a Limit
| Style | Recommended | Why |
|---|---|---|
| Conservative | 1 | One trade at a time. Full focus on quality. |
| Moderate | 2-3 | Allows some diversification across entries. |
| Aggressive | 5+ | Many concurrent positions. Higher capital risk. |
Example:
[meta]
name = "Single Position Focus"
max_open_positions = 1
# This strategy opens at most one position.
# Even if the entry trigger fires again, no new position is created
# until the current one is fully closed.
DCA -- Dollar-Cost Averaging
DCA is a technique where you buy more of an asset as the price drops, lowering your average entry price. In Botmarley, DCA is implemented using buy actions with average_price = true.
Why Use DCA?
Without DCA, if you buy at $50,000 and the price drops to $48,000, you need the price to return to $50,000 to break even. With DCA, you buy more at $48,000, which lowers your average entry price so you break even at a lower price.
DCA in Practice
Here is how a two-level DCA strategy works:
flowchart TD
A["open_long: Buy $100 at $50,000<br/>Entry Price = $50,000"] --> B{"Price drops 2%<br/>to $49,000?"}
B -- "Yes" --> C["buy: Add $200 at $49,000<br/>average_price = true<br/>New Entry = $49,333"]
B -- "No" --> D{"Price rises 3%<br/>from entry?"}
C --> E{"Price drops 4%<br/>to $48,000?"}
E -- "Yes" --> F["buy: Add $300 at $48,000<br/>average_price = true<br/>New Entry = $48,500"]
E -- "No" --> D
F --> D
D -- "Yes" --> G["sell 100%<br/>Take Profit"]
style A fill:#22c55e,color:#fff
style C fill:#4a9eff,color:#fff
style F fill:#4a9eff,color:#fff
style G fill:#ef4444,color:#fff
Entry Price Recalculation
When average_price = true, the entry price is recalculated as a weighted average:
new_entry_price = total_cost / total_quantity
Step-by-step example:
| Step | Action | Price | Amount | Total Cost | Total Qty | Avg Entry |
|---|---|---|---|---|---|---|
| 1 | open_long | $50,000 | $100 | $100 | 0.002 BTC | $50,000 |
| 2 | buy (DCA) | $49,000 | $200 | $300 | 0.006082 BTC | $49,327 |
| 3 | buy (DCA) | $48,000 | $300 | $600 | 0.012332 BTC | $48,654 |
After all three buys, the average entry is $48,654 instead of $50,000. The position needs only a 0% (break-even) to $48,654 recovery instead of a full return to $50,000.
DCA works best in markets that tend to recover (mean reversion). It can amplify losses in a prolonged downtrend. Always pair DCA with a stop-loss to limit maximum exposure.
max_count for DCA Levels
Use max_count on trigger to limit how many times a DCA level fires per position. Without it, a DCA trigger could fire repeatedly if the price oscillates around the threshold.
[[actions]]
type = "buy"
amount = "200 USDC"
average_price = true
[[actions.triggers]]
type = "pos_price_change"
value = "-2%"
max_count = 1 # Only fire once per position
With max_count = 1, this DCA level triggers exactly once. Even if the price bounces above and back below -2%, it will not trigger again for the same position.
Position Tracking
While a position is open, Botmarley continuously tracks:
Entry Price
The price at which the position was opened (or the weighted average if DCA has been applied). This is the reference point for all pos_price_change triggers.
Current P&L (Profit & Loss)
Calculated as:
P&L (%) = (current_price - entry_price) / entry_price * 100
For example, if entry is $48,654 and current price is $50,000:
P&L = (50000 - 48654) / 48654 * 100 = +2.77%
Position Size
The total quantity of the asset held and the total cost basis. This is used by percentage-based sell amounts ("50%" sells half the quantity).
Selling: Partial vs. Full Exit
Partial Sell
Selling less than 100% of the position lets you take some profit while keeping exposure:
# Sell half when profitable
[[actions]]
type = "sell"
amount = "50%"
[[actions.triggers]]
type = "pos_price_change"
value = "2%"
After this sell, 50% of the position remains open. The remaining position continues to be tracked with the same entry price.
Full Exit
Selling 100% closes the position entirely:
# Full exit on profit target
[[actions]]
type = "sell"
amount = "100%"
[[actions.triggers]]
type = "pos_price_change"
value = "5%"
After a full exit, the position is closed. The strategy's open_long action can now create a new position (subject to max_open_positions).
Scaling Out
You can combine multiple sell actions to scale out of a position gradually:
# Sell 30% at +2%
[[actions]]
type = "sell"
amount = "30%"
[[actions.triggers]]
type = "pos_price_change"
value = "2%"
# Sell 50% at +4%
[[actions]]
type = "sell"
amount = "50%"
[[actions.triggers]]
type = "pos_price_change"
value = "4%"
# Sell remaining 100% at +6%
[[actions]]
type = "sell"
amount = "100%"
[[actions.triggers]]
type = "pos_price_change"
value = "6%"
Percentage sells are relative to the current position size, not the original. If you sell 50% and then 50% again, you have sold 75% of the original position (50% + 50% of the remaining 50%).
Complete DCA Strategy Example
Here is a full strategy that demonstrates position management in action -- it enters on a Bollinger Band touch, DCA buys at -2%, -4%, and -6%, and exits at +3% profit or -10% stop-loss:
[meta]
name = "BB DCA with Stop Loss"
description = "Bollinger Band entry, 3-level DCA, profit target, and hard stop-loss"
max_open_positions = 1
# ENTRY: Price touches lower Bollinger Band
[[actions]]
type = "open_long"
amount = "100 USDC"
average_price = false
[[actions.triggers]]
indicator = "price"
operator = "<"
target = "bb_lower"
timeframe = "1h"
# DCA LEVEL 1: Buy more at -2% from entry
[[actions]]
type = "buy"
amount = "100 USDC"
average_price = true
[[actions.triggers]]
type = "pos_price_change"
value = "-2%"
max_count = 1
# DCA LEVEL 2: Buy more at -4% from entry
[[actions]]
type = "buy"
amount = "200 USDC"
average_price = true
[[actions.triggers]]
type = "pos_price_change"
value = "-4%"
max_count = 1
# DCA LEVEL 3: Buy more at -6% from entry
[[actions]]
type = "buy"
amount = "300 USDC"
average_price = true
[[actions.triggers]]
type = "pos_price_change"
value = "-6%"
max_count = 1
# TAKE PROFIT: Sell everything at +3%
[[actions]]
type = "sell"
amount = "100%"
[[actions.triggers]]
type = "pos_price_change"
value = "3%"
# STOP LOSS: Cut losses at -10%
[[actions]]
type = "sell"
amount = "100%"
[[actions.triggers]]
type = "pos_price_change"
value = "-10%"
How this plays out:
- Price drops below the lower Bollinger Band on the 1h chart -- the bot buys $100.
- If price continues dropping 2% from entry, the bot buys another $100 and averages the entry price down.
- If it drops 4% from entry, another $200 is added. At 6%, another $300.
- Maximum total investment: $100 + $100 + $200 + $300 = $700.
- If price recovers 3% from the (averaged) entry price, everything is sold for profit.
- If price drops 10% from entry without recovery, the stop-loss fires and cuts losses.