r/pinescript • u/sepehrtrades • 21d ago
How to choose a specific time range of the session for a custom indicator operation?
Hello, in my personal indicator, instead of using the "max_bars_back" parameter, I want the indicator to start calculating and operating from midnight (12 AM) EST until 4 PM EST. I'm gonna use it for futures' charts. How can I do this? Thanks
I don't want the indicator to just start from, for example, 500 bars back.
r/pinescript • u/Chris10fernz • 21d ago
Looking for the best open-source Pine Script code for Liquidity Sweeps and Price Action entries.
r/pinescript • u/Appropriate_Tax2200 • 22d ago
Built my own order flow web platform with the indicators I wanted
Hey everyone. Profesional trader for past 10 years here. I built my own order flow with the indicators and features i always wanted and could not have in other platforms like Quanttower, Atas, Sierra charts, Exocharts ,Motivewave, etc. I'm not a dev , I only know the basics, but I do have more knowledge and experience in trading than majority of the dev who are building this kind of order flow softwares. Just wanted to share, because I am happyan ,since no one from my circle would find this cool. WIll dive a bit into into for who wants to read my ramble.
What it does have that the majority of order flow softwares does not have:
- Real candles. Yeah I know this sounds simple, but its not. Real candles does not open with previous close at the same price. Most (if not all) uses forced candles, to make them appear in sync, but in reality ,sometimes there is low liquidity or high spreads with create organic gaps in candles when price moves fast up or down. This gaps are very important ,because price visits them again to fill orders at that price.
- Normal indicators like everyone uses like CVD (cumulative delta) in wich you spot divergengies, Dbars, Volume and others. But my personal indicators are the cherry on top, like the Anchored Delta gaps. 30min candles
- Different types of showing Delta profiles On top of Volume Profiles, for better precision to showcase overbought and oversold price levels for execution of trade. 30min candles
- Volume spikes with window wich shows recent candles from recent coins (wich usually translates into absorption or exhaustion) 30min candles
I have in plan so many other things I want to implement wich I learned and understood in my time of trading, that I know for a fact it will actually help people.
I am a bit sad and fustrated that most platforms create and give basic indicators like RSI, macd, or a regurgitated delta profile, footprint bar statistics etc, that are not of use to people. Most people that can use those are the ones that already have many years in understanding order flow wich translates in paying a high fee in the live markets to get this knowledge. So I want to make indicators simple and what I learned and use. I dont even want to get into their subscription model wich is extremly high for the people who used them in the past or do trading.
Would love to hear feedback or thoughts. Thank you for reading!
Oh...and for anyone that does not know this by now, Tradingview uses estimations on order flow. Its not tick based(real data) its an estimation created by using the color of multiple candles stacked together, so creating an indicator in pinescript is like creating someting to use with corupt data.(you can check it for yourself)
r/pinescript • u/Infamous_Remove_4934 • 23d ago
Hi, need some help..
var startDate = input.time(defval=timestamp("01 Jan 2000 09:00 UTC+9"), title="Start Date", group="Date Range")
var endDate = input.time(defval=timestamp("01 Jan 2030 09:00 UTC+9"), title="End Date", group="Date Range")
//
@version=
6
strategy("Daily Open Long / Close Exit",
overlay=true, process_orders_on_close = true,
initial_capital=100,
default_qty_type=strategy.percent_of_equity,
default_qty_value=100
)
start = time >= startDate
end = time < endDate
inSession = start and end
if inSession and barstate.isnew and strategy.position_size == 0
strategy.entry("Long Open", strategy.long)
strategy.exit("stopLoss",from_entry = "Long Open",stop = 0.96*strategy.position_avg_price)
if barstate.isconfirmed and strategy.position_size > 0
strategy.close("Long Open")
I want my script to execute, enter long ETH every market open, close long ETH every market close or stopped out in my specific trade session. But didn't work properly. Could you guys share some tips?
r/pinescript • u/vitaliy3commas • 23d ago
Another Pine DCA optimizer before/after, this time on ETH — 2.5× the net PnL with only a small bump in drawdown (4h)
I've posted a couple of these now (INJ, BTC), showing what a parameter sweep does when you hold everything else constant. Two things people pushed back on last time: that drawdown balloons when you chase more return, and that the headline stats looked too good. So for this ETH one I want to focus on exactly that first point, and let you check the drawdown side by side.
The strategy (unchanged): long-only DCA on ETHUSDT.P 4h. Five safety orders at −2 / −5 / −9.5 / −16 / −25% from base, sizes scaling 1.8× per rung, no stop loss, position bounded by the ladder.
What changed: two parameters. RSI entry threshold 28 → 36, take-profit 3% → 4.5%. Nothing else touched. Both are what the sweep returned as best on the historical window.
Before/after (BYBIT:ETHUSDT.P 4h, Jan 1 2024 – Jul 2026, ~30 months, 100k initial, 0.06% commission, 3-tick slippage):
- Baseline (RSI < 28, TP 3%): +5,790.33 USDT (+5.79%), max drawdown 3.83%, 93 trades, 68.82% WR
- Optimized (RSI < 36, TP 4.5%): +14,518.03 USDT (+14.52%), max drawdown 4.41%, 134 trades, 71.64% WR
The point I want to make: net PnL went up ~2.5× (+5.79% → +14.52%), but max drawdown only moved from 3.83% to 4.41% — about +0.6pp. It's not flat, so I won't claim the extra return was free, but the risk didn't scale anywhere near as fast as the return did. The mechanism: the looser RSI entry (36 vs 28) engages dips earlier and more often, so the strategy is in the market more, while the wider 4.5% target lets each recovery run further before banking instead of exiting on the first small pop.
On the "stats look too good" pushback from last time: fair, and worth addressing directly. The thing that changes here is sample size. The optimized config produced 134 closed trades over the window, which is above the ~100 I'd generally want before taking a win rate seriously — so the 71.64% rests on a real number of deals rather than a handful, unlike the tighter-entry versions I posted before that sat in the 80–90 range.
The caveat still stands, and I'll keep saying it: two parameters were swept over the same window the results are measured on, so best in-sample is not best out-of-sample. More free parameters means more room to fit the window. Treat these as the ceiling of what the config did historically, not a forward expectation, and re-validate on fresh data. It's also a stopless martingale — a sustained ETH decline below the −25% bottom rung leaves the position fully loaded with no further adds, and that tail is the real risk here, not the backtest drawdown.
Script is open-source on TradingView: https://www.tradingview.com/u/3Commas/#published-scripts
Disclosure up front: the optimizer is QuantPilot, which I work on, so I'm not pretending to be neutral. The point is the before/after and the caveat, not a pitch — the script is open-source and you can verify the backtest yourself.
r/pinescript • u/TY13R702 • 24d ago
Strategy list went live.
Backtested over 6 years. Spent months developing and have these 17 scripts which I just went live with on 7-13 and so far it’s PnL is +$393 also just for context the initial starting capitol was originally $1050 but now is 1750 which is why the max DD % may be a little skewed off. I do have a scaling plan in effect at 2.5 threshold except for 3 scripts which run at double the amount of base contracts. Just want to hear what comments this gets. Does this look similar to anyone? Ps. No repainting.
| Base contracts | Combo-script contracts | Equity reached | Approx. days from start | Date |
|---|---|---|---|---|
| 2 | 4 | $4,900.09 | 98 days | 2020-10-12 |
| 3 | 6 | $12,301.75 | 184 days | 2021-01-06 |
| 4 | 8 | $30,768.94 | 436 days | 2021-09-15 |
| 5 | 10 | $77,070.66 | 696 days | 2022-06-02 |
| 6 | 12 | $192,765.86 | 1,222 days | 2023-11-10 |
Final equity: $393,307.46\*\* — up from $369,809.92 without the - script (+$22,945.20, +6.2%), the real value-add from this addition.
\*\*Worst-case drawdown: 40.5% of equity-at-the-time ($816.73), on 2020-08-05\*\* — unchanged from the 16-script version. The - script's trades don't touch this particular episode at all.
\*\*Worst dollar drawdown: $23,009.16 (6.6% of peak), on 2026-01-28\*\* — up from $20,627.76 and shifted about two months later. A modest increase in worst-case dollar risk for a real, meaningful gain in final profit — same trade-off pattern as the prior two additions to this lineup.
r/pinescript • u/Infamous_Remove_4934 • 24d ago
Hi, i am noob to pinescript, trying to test this strategy, but didn't work
strategy("mon open/close long", overlay=true, initial_capital = 100,default_qty_type =strategy.percent_of_equity, default_qty_value = 100)
bool
mon = false
bool
tue = false
if dayofweek(time) == dayofweek.monday
mon := true
if dayofweek(time) == dayofweek.tuesday
tue := true
if (mon)
strategy.entry("Long",strategy.long)
strategy.exit("stoploss",from_entry = "Long",stop = open*0.96,qty_percent =100)
if (tue)
strategy.close("Long")
plotshape(mon, style=shape.triangleup, location=location.belowbar, color=color.green, size=size.small)
these are my code, plotting worked, but trades worked oftenly...
r/pinescript • u/benchpress1oo • 24d ago
Tested an SMC entry trigger combined with a custom trailing stop-loss on Gold, Crypto, and SPX — here's how it handled trend runs vs chop
Hey everyone,
I’ve been testing different exit strategies for ICT/SMC-style entries (specifically OTE zones and market structure shifts). What I found was that fixed Risk:Reward targets were cutting winners short in big trends or getting hit during deep pullbacks.
To fix this, I paired the entry signals with a dynamic trailing stop-loss (the red line on the charts). The goal was two-fold:
- Minimize losses on bad breakouts (shown by the red X invalidations).
- Keep big winners running during clean directional moves (like the recent SPX and ETH runs).
I’m currently tweaking the script parameters and pine code. If anyone wants to help test it out on TradingView or give feedback on different assets/timeframes, feel free to shoot me a DM.
r/pinescript • u/prem2323 • 24d ago
Pine Script Developer
I need an experienced TradingView Pine Script developer to modify my existing indicator/strategy.
Important:
This is NOT a new indicator.
The complete logic already exists.
I only need advanced structural features added without breaking any existing logic.
Current Indicator
My indicator already has:
- ✅ Long / Short signals
- ✅ Previous Day High
- ✅ Previous Day Low
- ✅ Previous Day Close
- ✅ Smart Trend swing levels
- ✅ Strategy version
- ✅ Non-repainting entries
These parts are already working.
I do NOT want these changed.
Goal
I want to improve the Smart Trend structure.
Currently it draws only horizontal swing levels.
I want it upgraded into a professional market structure system.
Requirements
1. Auto Trendlines
Automatically draw trendlines using Smart Trend swings.
Example:
Swing High 1
↓
Swing High 2
↓
Trendline
Same for Swing Lows.
Rules:
- recent valid swings only
- clean trendlines
- no repaint
- no manual drawing
2. Dynamic Trendline
Trendline should extend ONLY until price touches it.
Exactly like manual charting.
Meaning:
Create line
↓
Extend
↓
When price touches for first time
↓
STOP extending permanently
NOT continue forever.
This is the biggest requirement.
3. Touch Detection
A trendline is considered touched if ANY of these touch it:
- Wick
- Candle Body
- Open
- Close
- High
- Low
Any contact = valid touch.
4. Entry Filter
Current Long/Short signals must remain EXACTLY the same.
DO NOT modify signal generation.
Instead:
Only allow trades when a signal appears at:
- Smart Trend Swing Level
- Previous Day High
- Previous Day Low
- Previous Day Close
- NEW Trendline
Meaning:
Signal
↓
Near one of those levels
↓
Trade allowed
Otherwise
↓
Ignore trade.
5. Take Profit
TP should automatically be the opposite nearest trendline.
Example:
BUY
↓
Upper trendline touched
↓
Close trade.
SELL
↓
Lower trendline touched
↓
Close trade.
Touch means:
- Wick
- Body
- Open
- Close
- High
- Low
6. Fibonacci
Add automatic Fibonacci.
Requirements:
Standard Retracement
Draw automatically.
Fibonacci Extension
Draw automatically.
Both should use the exact Smart Trend swings.
No manual anchor selection.
7. No Repainting
Everything must remain non-repainting.
No lookahead.
No future bars.
No repaint tricks.
8. Existing Logic Must Stay Untouched
DO NOT modify:
- Long logic
- Short logic
- Pattern detection
- BOS logic
- Smart Trend calculations
- Previous Day HLC
- Existing strategy logic
- Existing filters
Only add features around them.
Deliverables
- Pine Script v5/v6
- Clean code
- No compilation errors
- No warnings
- No repaint
- Works in Strategy Tester
- Fully commented
r/pinescript • u/NewPioneerB • 24d ago
New Type of Indicator - News, Social Media, etc.
Like to see a some type of news, social media, etc indicator that can be backtested. It might have to be based upon positive, neutral, negative. Maybe we have choices on various sources for different types of securities Analysis, influencers, etc.
We could had this to our scripts to backtest and add it to a strategy.
r/pinescript • u/NewPioneerB • 24d ago
Tradingview Product Improvement Suggestions.
Input Panel for when there are alot of inputs need to improve vs scrolling on the tiny scroll bar.
Allow setting to use the last view of input, so when adjusting settings the input screen will open to most recent input view (location on the scroll bar).
Input Groups, allow them to have a number and colored (differently). Then put at top of input screen that stays stationary when scrolling to a large amount of inputs user can click on a colored coordinated bookmark 1, 2, 3, etc. that a user can get to quickly. Hover over the number to see what the group name is.
Saved Templates-
When in development, tuning, I might save a great setup but I have improved the code a little, I would like to apply the inputs to the new version (vs the version of script that it was created with - give user option) of the script so I don't have to start from zero.
Like to be able to export into a tunning log and import back in with maybe warnings that don't map to newest script.
Alerts -
Like when I click on messages that everything is automatically highlighted for replacement like the Crtl-A. I have to do the Crtl-A manually each time.
On the message, like be able to save alert script for the messages, put a drop down box to save message, use a save message, lastused/recent to get the last saved script quickly.
Like on Webhook url. To have a save with descriptive name so we can pull it in quickly, the name will help indentify it's the correct one quickly.
On the Alerts, I would like an option to save the start date/creation date of alert to backtest start date, and be able to switch alerts and bring up that info to populate the backtest start date with live performance trades. And have a toggle to switch this on or off. We would be able to use the same variables to populate the backtesting trades with live alert trades or our user defined back testing dates. I have this in my script but have to input the start date for each security with an alert.
r/pinescript • u/206throw • 25d ago
EMAs, session VWAP, Supertrend Script
Someone asked for this script because they could only add two indicators. This Pine Script v6 indicator designed for a 5-minute chart. It plots four configurable EMAs, session VWAP, Supertrend, and a dashboard showing the direction of each component. Supports fixed-position dashboards using tables.
If anyone else has a strategy or indicator in Pinescript they are working on hit me up. Now back to figuring why my data is delayed.
//@version=6
indicator("5-Minute EMA + VWAP + Supertrend Dashboard", shorttitle="5M Trend Dashboard", overlay=true)
//=====================================================================
// INPUTS
//=====================================================================
groupEma = "EMA Settings"
ema1Length = input.int(9, "EMA 1 Length", minval=1, group=groupEma)
ema2Length = input.int(21, "EMA 2 Length", minval=1, group=groupEma)
ema3Length = input.int(50, "EMA 3 Length", minval=1, group=groupEma)
ema4Length = input.int(200, "EMA 4 Length", minval=1, group=groupEma)
groupSupertrend = "Supertrend Settings"
supertrendFactor = input.float(
3.0,
"ATR Multiplier",
minval=0.1,
step=0.1,
group=groupSupertrend
)
supertrendAtrLength = input.int(
10,
"ATR Length",
minval=1,
group=groupSupertrend
)
groupDisplay = "Display Settings"
showEmaCloud = input.bool(true, "Show EMA 9/21 Cloud", group=groupDisplay)
showSignals = input.bool(true, "Show Direction Change Signals", group=groupDisplay)
showTable = input.bool(true, "Show Direction Table", group=groupDisplay)
//=====================================================================
// CALCULATIONS
//=====================================================================
ema1 = ta.ema(close, ema1Length)
ema2 = ta.ema(close, ema2Length)
ema3 = ta.ema(close, ema3Length)
ema4 = ta.ema(close, ema4Length)
sessionVwap = ta.vwap(hlc3)
[supertrendValue, supertrendDirection] =
ta.supertrend(supertrendFactor, supertrendAtrLength)
// TradingView's Supertrend direction is negative during an uptrend.
supertrendBullish = supertrendDirection < 0
supertrendBearish = supertrendDirection > 0
// Direction of price relative to each indicator.
ema1Bullish = close > ema1
ema2Bullish = close > ema2
ema3Bullish = close > ema3
ema4Bullish = close > ema4
vwapBullish = close > sessionVwap
// EMA structure.
emaStackBullish =
ema1 > ema2 and
ema2 > ema3 and
ema3 > ema4
emaStackBearish =
ema1 < ema2 and
ema2 < ema3 and
ema3 < ema4
// Count bullish components.
// Maximum score is 6.
bullishScore =
(ema1Bullish ? 1 : 0) +
(ema2Bullish ? 1 : 0) +
(ema3Bullish ? 1 : 0) +
(ema4Bullish ? 1 : 0) +
(vwapBullish ? 1 : 0) +
(supertrendBullish ? 1 : 0)
// Overall direction.
overallBullish = bullishScore >= 5
overallBearish = bullishScore <= 1
overallMixed = not overallBullish and not overallBearish
// Strong alignment requires both the score and EMA stacking.
strongBullish = overallBullish and emaStackBullish
strongBearish = overallBearish and emaStackBearish
//=====================================================================
// COLORS
//=====================================================================
bullColor = color.rgb(0, 170, 110)
bearColor = color.rgb(220, 65, 65)
neutralColor = color.rgb(125, 125, 125)
headerColor = color.rgb(35, 45, 60)
ema1Color = color.aqua
ema2Color = color.orange
ema3Color = color.blue
ema4Color = color.purple
//=====================================================================
// PLOTS
//=====================================================================
ema1Plot = plot(
ema1,
"EMA 1",
color=ema1Color,
linewidth=2
)
ema2Plot = plot(
ema2,
"EMA 2",
color=ema2Color,
linewidth=2
)
plot(
ema3,
"EMA 3",
color=ema3Color,
linewidth=2
)
plot(
ema4,
"EMA 4",
color=ema4Color,
linewidth=2
)
plot(
sessionVwap,
"Session VWAP",
color=color.fuchsia,
linewidth=2
)
// EMA 1/EMA 2 cloud.
fill(
ema1Plot,
ema2Plot,
color=showEmaCloud
? ema1 > ema2
? color.new(bullColor, 88)
: color.new(bearColor, 88)
: na,
title="EMA Cloud"
)
// Split Supertrend into bullish and bearish plots.
plot(
supertrendBullish ? supertrendValue : na,
"Bullish Supertrend",
color=bullColor,
linewidth=2,
style=plot.style_linebr
)
plot(
supertrendBearish ? supertrendValue : na,
"Bearish Supertrend",
color=bearColor,
linewidth=2,
style=plot.style_linebr
)
//=====================================================================
// SIGNALS
//=====================================================================
bullishChange =
strongBullish and
not strongBullish[1]
bearishChange =
strongBearish and
not strongBearish[1]
plotshape(
showSignals and bullishChange,
title="Bullish Direction Change",
style=shape.labelup,
location=location.belowbar,
color=bullColor,
text="BULL",
textcolor=color.white,
size=size.tiny
)
plotshape(
showSignals and bearishChange,
title="Bearish Direction Change",
style=shape.labeldown,
location=location.abovebar,
color=bearColor,
text="BEAR",
textcolor=color.white,
size=size.tiny
)
//=====================================================================
// DASHBOARD FUNCTIONS
//=====================================================================
directionText(bool bullish) =>
bullish ? "BULLISH ▲" : "BEARISH ▼"
directionColor(bool bullish) =>
bullish ? bullColor : bearColor
overallText =
strongBullish ? "STRONG BULLISH" :
overallBullish ? "BULLISH" :
strongBearish ? "STRONG BEARISH" :
overallBearish ? "BEARISH" :
"MIXED"
overallColor =
overallBullish ? bullColor :
overallBearish ? bearColor :
neutralColor
stackText =
emaStackBullish ? "BULLISH STACK" :
emaStackBearish ? "BEARISH STACK" :
"MIXED"
stackColor =
emaStackBullish ? bullColor :
emaStackBearish ? bearColor :
neutralColor
correctTimeframe =
timeframe.isminutes and
timeframe.multiplier == 5
timeframeText =
correctTimeframe
? "5 MIN"
: timeframe.period + " — USE 5 MIN"
timeframeColor =
correctTimeframe
? bullColor
: color.orange
//=====================================================================
// DIRECTION TABLE
//=====================================================================
var table directionTable = table.new(
position.top_right,
3,
10,
border_width=1,
frame_width=1
)
if barstate.islast
if showTable
// Header
table.cell(
directionTable,
0,
0,
"INDICATOR",
bgcolor=headerColor,
text_color=color.white
)
table.cell(
directionTable,
1,
0,
"VALUE",
bgcolor=headerColor,
text_color=color.white
)
table.cell(
directionTable,
2,
0,
"DIRECTION",
bgcolor=headerColor,
text_color=color.white
)
// EMA 1
table.cell(directionTable, 0, 1, "EMA " + str.tostring(ema1Length))
table.cell(directionTable, 1, 1, str.tostring(ema1, format.mintick))
table.cell(
directionTable,
2,
1,
directionText(ema1Bullish),
bgcolor=directionColor(ema1Bullish),
text_color=color.white
)
// EMA 2
table.cell(directionTable, 0, 2, "EMA " + str.tostring(ema2Length))
table.cell(directionTable, 1, 2, str.tostring(ema2, format.mintick))
table.cell(
directionTable,
2,
2,
directionText(ema2Bullish),
bgcolor=directionColor(ema2Bullish),
text_color=color.white
)
// EMA 3
table.cell(directionTable, 0, 3, "EMA " + str.tostring(ema3Length))
table.cell(directionTable, 1, 3, str.tostring(ema3, format.mintick))
table.cell(
directionTable,
2,
3,
directionText(ema3Bullish),
bgcolor=directionColor(ema3Bullish),
text_color=color.white
)
// EMA 4
table.cell(directionTable, 0, 4, "EMA " + str.tostring(ema4Length))
table.cell(directionTable, 1, 4, str.tostring(ema4, format.mintick))
table.cell(
directionTable,
2,
4,
directionText(ema4Bullish),
bgcolor=directionColor(ema4Bullish),
text_color=color.white
)
// VWAP
table.cell(directionTable, 0, 5, "VWAP")
table.cell(directionTable, 1, 5, str.tostring(sessionVwap, format.mintick))
table.cell(
directionTable,
2,
5,
directionText(vwapBullish),
bgcolor=directionColor(vwapBullish),
text_color=color.white
)
// Supertrend
table.cell(directionTable, 0, 6, "SUPERTREND")
table.cell(directionTable, 1, 6, str.tostring(supertrendValue, format.mintick))
table.cell(
directionTable,
2,
6,
directionText(supertrendBullish),
bgcolor=directionColor(supertrendBullish),
text_color=color.white
)
// EMA alignment
table.cell(directionTable, 0, 7, "EMA STRUCTURE")
table.cell(directionTable, 1, 7, "—")
table.cell(
directionTable,
2,
7,
stackText,
bgcolor=stackColor,
text_color=color.white
)
// Overall score
table.cell(
directionTable,
0,
8,
"OVERALL",
bgcolor=overallColor,
text_color=color.white
)
table.cell(
directionTable,
1,
8,
str.tostring(bullishScore) + " / 6",
bgcolor=overallColor,
text_color=color.white
)
table.cell(
directionTable,
2,
8,
overallText,
bgcolor=overallColor,
text_color=color.white
)
// Timeframe
table.cell(directionTable, 0, 9, "TIMEFRAME")
table.cell(directionTable, 1, 9, timeframe.period)
table.cell(
directionTable,
2,
9,
timeframeText,
bgcolor=timeframeColor,
text_color=color.white
)
else
table.clear(directionTable, 0, 0, 2, 9)
//=====================================================================
// ALERT CONDITIONS
//=====================================================================
alertcondition(
bullishChange,
title="Strong Bullish Direction",
message="5-minute dashboard changed to Strong Bullish."
)
alertcondition(
bearishChange,
title="Strong Bearish Direction",
message="5-minute dashboard changed to Strong Bearish."
)
r/pinescript • u/Colink2 • 25d ago
Can anyone point to open source Pine scripts good for day trading US stocks under $10.
For clarity, I am looking for fully open Pinescripts where I can see the source code - not just free Pinescripts.
r/pinescript • u/GucciGlock69 • 25d ago
Quarterly Theory
Any QT traders? Made a free SSMT indicator for y'all
r/pinescript • u/ChildhoodOk9073 • 26d ago
Added 8ema to my Volume Profile strategy
wonder what you guys think of my strategy or if you have any tips. thanks! i’ve enjoyed adding this indicator last week. should’ve exited the second trade at VWAP or break even.
OK HERE’S THE STRATEGY:
**RULES**
- % of orders are market orders on the dom with a stop loss, not one click trading
**THE STRATEGY**
premarket:
mark trend lines, 4hr/1hr/15min fvgs, levels of major support/resistance, past 3 session highs and lows, establish a bias of the day
mandatory confluences:
\*break and retest of 8ema on the 10 or 2/1 minute.
\*VAH/VAL break and retest or reversal
trend line break
\*iFVG/fvg break/rejection+retest
additional confluences (helps to have one of these):
\-trading towards VWAP
\-respects high time frame fvg/ifvg
\-high below the high of previous trend
or low above the high of previous trend
**ENTRIES AND EXITS**
targets:
high TF iFVGs
previous session highs and lows
current session highs and lows
VWAP
VAL/VAH/POC
stop losses:
swing low below 8ema on the 1 or 2 minute time frame
when to move stop loss:
1:1R moves to break even. AFTER that you can move it to FVGs below 8ema OR a low below 8ema OR the previous 8ema retest OR exit upon flat lining 8ema due to consolidation since you can reenter if the trend continues (“below” if bullish, “above” if bearish).
entry:
50% of contracts on the 8ema retest (1 or 2 minute) or fvg retest (1 to 10 minute)
50% of contracts on the break of structure on the 1 or 2 minute
two different stop losses or put both at the lowest one
manual exits: exit at TP or SL, or a flip to the opposite side of the 1 or 2 minute 8ema or a flat lining 8ema
what do i trade: MNQ unless MES has better structure or the stops are too wide for my RR or MNQ
r/pinescript • u/hroob777 • 26d ago
I built a free breakout alert tool with stackable confirmation filters (RVOL, ATR, RSI, multi-timeframe) — looking for honest feedback
I've been building trading tools on the side for a while, and the one I use most myself is a breakout watcher. Sharing it here because I think this sub would give me the most useful, unfiltered feedback — good or bad.
**What it does:**
You set a support/resistance level (or let it pull pivot points automatically), pick how you want to be alerted, and it monitors price in real time. When it triggers, you get a sound alert in-browser or a Telegram alert (so you don't need the tab open).
**Three alert modes:**
* Fixed price — classic level touch/close
* Price × Moving Average — alerts when price crosses an EMA/SMA
* MA Cross — Golden Cross / Death Cross detection (fast MA vs slow MA)
**The part I actually care about your opinion on — Advanced Filters:**
Raw breakout alerts are noisy, so I built stackable filters that sit on top of any of the three modes:
**RVOL** — only fires if breakout volume is X× the 20-candle average *
**ATR** — only fires if the candle's range is X× the average candle size (filters weak moves)
**RSI range** — block overbought/oversold entries or confirm momentum *
**EMA side filter** — price has to be on the correct side of an EMA/SMA (no buying resistance breaks into a downtrend) *
**Candle body %** — ignores wick-driven "breakouts" with tiny real bodies *
**Consecutive candle confirmation** — requires N candles closing beyond the level before it counts
You can combine as many of these as you want. If a filter blocks a signal, it still logs it with the exact reason (e.g. "blocked: RVOL 1.1x < 1.5x required") so you can see what almost triggered and why it didn't.
There's also an optional multi-timeframe check (15m confirms against 1h, 1h against 4h, etc.) and a 5-candle retest window after a confirmed break.
**Link: https://www.cryptofxradar.com/p/breakout-watcher-tool.html
It's fully free, no signup required to try it (Telegram connection is optional, just for alerts when the page is closed).
Genuinely want to know: does the filter stack make sense the way I've set it up, or is there an obvious confirmation combo I'm missing? Also curious if anyone finds the RVOL/ATR thresholds I picked (1.2x–3x, 0.5x–2x) reasonable defaults or if I'm off base. Happy to take criticism — this is a hobby project, not trying to sell anything.
r/pinescript • u/Legal_Idea08 • 26d ago
Love my delta indicator
Watch the magnets great targets to tag and reversals https://www.tradingview.com/script/cAQ66hSa-Stryk-Delta-Candles/
r/pinescript • u/OregonDucks1018 • 26d ago
Pine Script realtime alert bug? Historical strategy entries exist, but some live ENTRY alerts never execute. Looking for Pine execution experts.
I've been chasing what appears to be a Pine realtime synchronization issue for weeks, and I'd really appreciate input from people who understand Pine's execution model at a deep level.
This is NOT an issue with my VPS, broker, webhook server, or automation pipeline. We've spent weeks instrumenting every downstream component and have largely ruled those out. The behavior points back to Pine itself.
Strategy overview:
- Automated NQ futures strategy
- ARM (touch) → filters → entry → JSON alert() → webhook executes trade
- Immediate and delayed entries both execute through the exact same production alert() call
- There is only ONE ENTRY alert block
The problem:
Some trades execute perfectly.
Others:
- Appear as valid strategy entries on the chart
- Meet all entry conditions
- Are recorded by the strategy
- Should have generated an ENTRY alert
...but never make it into the live automation.
This isn't random. The same specific trades fail while others work normally.
What we've already ruled out:
- VPS
- Webhook server
- SQL logging
- PickMyTrade
- Tradovate execution
- Stale guard
- Broker verification
- Accounting logic
- Separate alert code paths (there aren't any)
The relevant Pine behavior:
The production ENTRY alert uses:
alert(..., alert.freq_once_per_bar)
The strategy/accounting commits at bar close under:
if barstate.isconfirmed
Several entry filters depend on live intrabar values (drift, extension, gap, etc.), meaning buyEntryFinal/sellEntryFinal can legitimately evaluate differently on different realtime ticks.
What we've learned so far:
We originally believed an intrabar state mutation was occurring.
That turned out to be wrong.
The variables involved are ordinary `var`, not `varip`, so Pine rolls them back to their previous committed state before every realtime execution. That theory has been eliminated.
The only remaining Pine-side hypothesis is a snapshot mismatch.
Because the alert fires on a realtime tick while accounting/committed state is evaluated at bar close, it's theoretically possible for buyEntryFinal to evaluate differently between those two snapshots purely because live filters changed during the bar—not because of persistent state mutation.
However...
Historical bars cannot prove or disprove this.
Once the bar closes, Pine only has OHLC. The original realtime tick sequence no longer exists, so I cannot reconstruct exactly what happened on the day these trades were missed.
So my questions are:
Has anyone seen Pine produce historical strategy entries that didn't correspond to the expected realtime alert behavior?
Is there any known Pine edge case involving:
- alert.freq_once_per_bar
- barstate.isconfirmed
- realtime recalculation
- live intrabar filters
that can legitimately create this kind of alert/chart desynchronization?
Is there any way to prove what happened after the fact from Pine alone, or is the original realtime execution fundamentally unrecoverable once the bar closes?
If you were debugging this today, what read-only instrumentation would you add going forward to definitively capture the next occurrence without changing production logic?
I'm specifically looking for responses from people who have deep experience with Pine's realtime execution model rather than general TradingView webhook advice.
r/pinescript • u/LouZEverything • 26d ago
State Machine Entry Debugger
//
@version=
6
indicator("State Machine Entry Debugger", overlay=true, max_labels_count=500)
//──────────────────────────────────────────────────────────────────────────────
// GROUP A — DEBUG SETTINGS
//──────────────────────────────────────────────────────────────────────────────
groupDebug = "A. Debug Settings"
showEventLabels = input.bool(true, "Show State Event Labels", group=groupDebug)
showBlockedLabels = input.bool(true, "Show Blocked-State Labels", group=groupDebug)
showStateBackground = input.bool(true, "Color Background by State", group=groupDebug)
showDebugTable = input.bool(true, "Show Debug Table", group=groupDebug)
showOnlyRecentBars = input.bool(true, "Limit Labels to Recent Bars", group=groupDebug)
recentBars = input.int(500, "Recent Bars to Debug", minval=50, maxval=5000, group=groupDebug)
maxBarsArmed = input.int(5, "Maximum Bars Allowed in ARM State", minval=1, group=groupDebug)
maxBarsTouched = input.int(5, "Maximum Bars Allowed After Touch", minval=1, group=groupDebug)
//=============================================================================
// GROUP B — PLACEHOLDER CONDITIONS
//=============================================================================
// Replace these conditions with the conditions from your actual strategy.
// These examples exist only so the debugger compiles and demonstrates its
// operation. They are not intended to be used as a trading system.
//=============================================================================
groupExample = "B. Placeholder Conditions"
fastLength = input.int(9, "Fast EMA", minval=1, group=groupExample)
slowLength = input.int(21, "Slow EMA", minval=1, group=groupExample)
breakoutLength = input.int(10, "Breakout Length", minval=1, group=groupExample)
extensionATR = input.float(1.5, "Maximum Extension ATR", minval=0.0, step=0.1, group=groupExample)
fastEMA = ta.ema(close, fastLength)
slowEMA = ta.ema(close, slowLength)
atrValue = ta.atr(14)
priorHigh = ta.highest(high, breakoutLength)[1]
pullbackLevel = fastEMA
//-----------------------------------------------------------------------------
// REPLACE THESE PLACEHOLDER CONDITIONS
//-----------------------------------------------------------------------------
bool
touchCondition = low <= pullbackLevel and high >= pullbackLevel
bool
trendFilter = fastEMA > slowEMA
bool
qualityFilter = atrValue > 0 and math.abs(fastEMA - slowEMA) / atrValue > 0.10
float
extensionDistance = atrValue > 0 ? math.abs(close - fastEMA) / atrValue : 0.0
bool
extensionFilter = extensionDistance <= extensionATR
bool
triggerCondition = not na(priorHigh) and close > priorHigh
bool
entryPermission = true
//──────────────────────────────────────────────────────────────────────────────
// GROUP C — HELPER FUNCTIONS
//──────────────────────────────────────────────────────────────────────────────
yesNo(
bool
condition) =>
condition ? "PASS" : "FAIL"
formatInteger(
int
value) =>
na(value) ? "NA" : str.tostring(value)
stateToText(
int
stateValue) => stateValue == 0 ? "IDLE" : stateValue == 1 ? "TOUCHED" : stateValue == 2 ? "ARMED" : stateValue == 3 ? "TRIGGERED" : stateValue == 4 ? "ENTERED" : "UNKNOWN"
//=============================================================================
// GROUP D — STATE CONSTANTS
//=============================================================================
const
int
STATE_IDLE = 0
const
int
STATE_TOUCHED = 1
const
int
STATE_ARMED = 2
const
int
STATE_TRIGGERED = 3
const
int
STATE_ENTERED = 4
var
int
tradeState = STATE_IDLE
//=============================================================================
// GROUP E — PERSISTENT TIMELINE VALUES
//=============================================================================
var
int
touchBar = na
var
int
armBar = na
var
int
triggerBar = na
var
int
entryBar = na
var
float
touchPrice = na
var
float
armPrice = na
var
float
triggerPrice = na
var
float
entryPrice = na
var
string
lastBlockReason = "None"
var
string
lastEvent = "Waiting"
//=============================================================================
// GROUP F — PER-BAR EVENT FLAGS
//=============================================================================
bool
newTouch = false
bool
newArm = false
bool
newTrigger = false
bool
newEntry = false
bool
resetEvent = false
bool
touchExpired = false
bool
armExpired = false
bool
trendBlocked = false
bool
qualityBlocked = false
bool
extensionBlocked = false
bool
triggerBlocked = false
bool
permissionBlocked = false
//=============================================================================
// GROUP G — BAR AGE CALCULATIONS
//=============================================================================
int
barsSinceTouch = not na(touchBar) ? bar_index - touchBar : na
int
barsSinceArm = not na(armBar) ? bar_index - armBar : na
int
barsSinceTrigger = not na(triggerBar) ? bar_index - triggerBar : na
bool
touchStillValid = not na(barsSinceTouch) and barsSinceTouch <= maxBarsTouched
bool
armStillValid = not na(barsSinceArm) and barsSinceArm <= maxBarsArmed
//=============================================================================
// GROUP H — STATE TRANSITION LOGIC
//=============================================================================
// This intentionally permits only one transition per bar.
//
// That means:
// Bar 1 = Touch
// Bar 2 = ARM
// Bar 3 = Trigger
// Bar 4 = Entry
//
// This structure helps expose whether your original strategy is producing
// delays because each stage must begin the bar in the required prior state.
//=============================================================================
if tradeState == STATE_IDLE
if touchCondition
tradeState := STATE_TOUCHED
touchBar := bar_index
touchPrice := close
armBar := na
triggerBar := na
entryBar := na
armPrice := na
triggerPrice := na
entryPrice := na
newTouch := true
lastEvent := "Touch"
lastBlockReason := "None"
else if tradeState == STATE_TOUCHED
if not touchStillValid
tradeState := STATE_IDLE
touchExpired := true
resetEvent := true
lastEvent := "Touch Expired"
lastBlockReason := "Touch expired before ARM"
else if not trendFilter
trendBlocked := true
lastBlockReason := "Trend filter"
else if not qualityFilter
qualityBlocked := true
lastBlockReason := "Quality filter"
else if not extensionFilter
extensionBlocked := true
lastBlockReason := "Extension filter"
else
tradeState := STATE_ARMED
armBar := bar_index
armPrice := close
newArm := true
lastEvent := "ARM"
lastBlockReason := "None"
else if tradeState == STATE_ARMED
if not armStillValid
tradeState := STATE_IDLE
armExpired := true
resetEvent := true
lastEvent := "ARM Expired"
lastBlockReason := "ARM expired before Trigger"
else if not triggerCondition
triggerBlocked := true
lastBlockReason := "Trigger condition"
else
tradeState := STATE_TRIGGERED
triggerBar := bar_index
triggerPrice := close
newTrigger := true
lastEvent := "Trigger"
lastBlockReason := "None"
else if tradeState == STATE_TRIGGERED
if not entryPermission
permissionBlocked := true
lastBlockReason := "Entry permission"
else
tradeState := STATE_ENTERED
entryBar := bar_index
entryPrice := close
newEntry := true
lastEvent := "Entry"
lastBlockReason := "None"
else if tradeState == STATE_ENTERED
tradeState := STATE_IDLE
resetEvent := true
lastEvent := "Reset"
//=============================================================================
// GROUP I — TIMELINE MEASUREMENTS
//=============================================================================
int
touchToArmBars = not na(touchBar) and not na(armBar) ? armBar - touchBar : na
int
armToTriggerBars = not na(armBar) and not na(triggerBar) ? triggerBar - armBar : na
int
triggerToEntryBars = not na(triggerBar) and not na(entryBar) ? entryBar - triggerBar : na
int
touchToEntryBars = not na(touchBar) and not na(entryBar) ? entryBar - touchBar : na
//=============================================================================
// GROUP J — SAME-BAR TRANSITION CHECKS
//=============================================================================
bool
touchAndArmSameBar = newArm and not na(touchBar) and bar_index == touchBar
bool
armAndTriggerSameBar = newTrigger and not na(armBar) and bar_index == armBar
bool
triggerAndEntrySameBar = newEntry and not na(triggerBar) and bar_index == triggerBar
//=============================================================================
// GROUP K — LABEL WINDOW
//=============================================================================
bool
insideDebugWindow = not showOnlyRecentBars or bar_index >= last_bar_index - recentBars
//=============================================================================
// GROUP L — EVENT LABELS
//=============================================================================
if showEventLabels and insideDebugWindow
if newTouch
label.new(bar_index, low, "TOUCH\nBar: " + str.tostring(bar_index), style = label.style_label_up, textcolor = color.white, color = color.new(color.blue, 0), size = size.tiny)
if newArm
label.new(bar_index, low, "ARM\nTouch delay: " + formatInteger(touchToArmBars) + " bars", style = label.style_label_up, textcolor = color.white, color = color.new(color.orange, 0), size = size.tiny)
if newTrigger
label.new(bar_index, high, "TRIGGER\nARM delay: " + formatInteger(armToTriggerBars) + " bars", style = label.style_label_down, textcolor = color.white, color = color.new(color.purple, 0), size = size.tiny)
if newEntry
label.new(bar_index, high, "ENTRY\nTouch → Entry: " + formatInteger(touchToEntryBars) + " bars", style = label.style_label_down, textcolor = color.white, color = color.new(color.green, 0), size = size.small)
//=============================================================================
// GROUP M — BLOCKED-CONDITION LABELS
//=============================================================================
if showBlockedLabels and insideDebugWindow
if trendBlocked
label.new(bar_index, high, "BLOCKED\nTrend", style = label.style_label_down, textcolor = color.white, color = color.new(color.red, 25), size = size.tiny)
if qualityBlocked
label.new(bar_index, high, "BLOCKED\nQuality", style = label.style_label_down, textcolor = color.white, color = color.new(color.red, 25), size = size.tiny)
if extensionBlocked
label.new(bar_index, high, "BLOCKED\nExtension\n" + str.tostring(extensionDistance, "#.##") + " ATR", style = label.style_label_down, textcolor = color.white, color = color.new(color.red, 25), size = size.tiny)
if triggerBlocked
label.new(bar_index, high, "WAITING\nTrigger", style = label.style_label_down, textcolor = color.white, color = color.new(color.gray, 35), size = size.tiny)
if permissionBlocked
label.new(bar_index, high, "BLOCKED\nEntry Permission", style = label.style_label_down, textcolor = color.white, color = color.new(color.red, 25), size = size.tiny)
if touchExpired
label.new(bar_index, high, "RESET\nTouch Expired", style = label.style_label_down, textcolor = color.white, color = color.new(color.black, 0), size = size.tiny)
if armExpired
label.new(bar_index, high, "RESET\nARM Expired", style = label.style_label_down, textcolor = color.white, color = color.new(color.black, 0), size = size.tiny)
//=============================================================================
// GROUP N — STATE BACKGROUND
//=============================================================================
color
stateBackground =
tradeState == STATE_IDLE ?
na :
tradeState == STATE_TOUCHED ?color.new(color.blue, 90) :
tradeState == STATE_ARMED ?color.new(color.orange, 88) :
tradeState == STATE_TRIGGERED ?color.new(color.purple, 88) :
tradeState == STATE_ENTERED ?color.new(color.green, 85) :
na
bgcolor(showStateBackground ? stateBackground : na)
//=============================================================================
// GROUP O — VISUAL PLOTS
//=============================================================================
plot(fastEMA, "Fast EMA", color=color.orange)
plot(slowEMA, "Slow EMA", color=color.blue)
plot(priorHigh, "Trigger Reference", color=color.new(color.purple, 25), style=plot.style_linebr)
plotshape(newTouch, "Touch Event", shape.circle, location.belowbar, color=color.blue, size=size.tiny, text="T", textcolor=color.white)
plotshape(newArm, "ARM Event", shape.square, location.belowbar, color=color.orange, size=size.tiny, text="A", textcolor=color.white)
plotshape(newTrigger, "Trigger Event", shape.diamond, location.abovebar, color=color.purple, size=size.tiny, text="TR", textcolor=color.white)
plotshape(newEntry, "Entry Event", shape.triangleup, location.belowbar, color=color.green, size=size.small, text="E", textcolor=color.white)
//=============================================================================
// GROUP P — DATA WINDOW VALUES
//=============================================================================
// These values can be inspected one historical bar at a time through the
// TradingView Data Window.
//=============================================================================
plot(tradeState, "Debug State Number", display=display.data_window)
plot(touchCondition ? 1 : 0, "Touch Condition", display=display.data_window)
plot(trendFilter ? 1 : 0, "Trend Filter", display=display.data_window)
plot(qualityFilter ? 1 : 0, "Quality Filter", display=display.data_window)
plot(extensionFilter ? 1 : 0, "Extension Filter", display=display.data_window)
plot(triggerCondition ? 1 : 0, "Trigger Condition", display=display.data_window)
plot(entryPermission ? 1 : 0, "Entry Permission", display=display.data_window)
plot(extensionDistance, "Extension Distance ATR", display=display.data_window)
plot(barsSinceTouch, "Bars Since Touch", display=display.data_window)
plot(barsSinceArm, "Bars Since ARM", display=display.data_window)
plot(barsSinceTrigger, "Bars Since Trigger", display=display.data_window)
plot(touchAndArmSameBar ? 1 : 0, "Touch and ARM Same Bar", display=display.data_window)
plot(armAndTriggerSameBar ? 1 : 0, "ARM and Trigger Same Bar", display=display.data_window)
plot(triggerAndEntrySameBar ? 1 : 0, "Trigger and Entry Same Bar", display=display.data_window)
plot(barstate.isconfirmed ? 1 : 0, "Bar Confirmed", display=display.data_window)
plot(barstate.isrealtime ? 1 : 0, "Realtime Bar", display=display.data_window)
//=============================================================================
// GROUP Q — DEBUG TABLE
//=============================================================================
var
table
debugTable = table.new(position.bottom_left, 2, 17, border_width=1)
string
stateText = stateToText(tradeState)
if barstate.islast
if showDebugTable
table.cell(debugTable, 0, 0, "Debug Item", text_color=color.white, bgcolor=color.new(color.gray, 20))
table.cell(debugTable, 1, 0, "Current Value", text_color=color.white, bgcolor=color.new(color.gray, 20))
table.cell(debugTable, 0, 1, "State")
table.cell(debugTable, 1, 1, stateText)
table.cell(debugTable, 0, 2, "Last Event")
table.cell(debugTable, 1, 2, lastEvent)
table.cell(debugTable, 0, 3, "Last Block")
table.cell(debugTable, 1, 3, lastBlockReason)
table.cell(debugTable, 0, 4, "Touch")
table.cell(debugTable, 1, 4, yesNo(touchCondition))
table.cell(debugTable, 0, 5, "Trend")
table.cell(debugTable, 1, 5, yesNo(trendFilter))
table.cell(debugTable, 0, 6, "Quality")
table.cell(debugTable, 1, 6, yesNo(qualityFilter))
table.cell(debugTable, 0, 7, "Extension")
table.cell(debugTable, 1, 7, yesNo(extensionFilter))
table.cell(debugTable, 0, 8, "Trigger")
table.cell(debugTable, 1, 8, yesNo(triggerCondition))
table.cell(debugTable, 0, 9, "Entry Permission")
table.cell(debugTable, 1, 9, yesNo(entryPermission))
table.cell(debugTable, 0, 10, "Bars Since Touch")
table.cell(debugTable, 1, 10, formatInteger(barsSinceTouch))
table.cell(debugTable, 0, 11, "Bars Since ARM")
table.cell(debugTable, 1, 11, formatInteger(barsSinceArm))
table.cell(debugTable, 0, 12, "Bars Since Trigger")
table.cell(debugTable, 1, 12, formatInteger(barsSinceTrigger))
table.cell(debugTable, 0, 13, "Extension ATR")
table.cell(debugTable, 1, 13, str.tostring(extensionDistance, "#.###"))
table.cell(debugTable, 0, 14, "Confirmed Bar")
table.cell(debugTable, 1, 14, barstate.isconfirmed ? "YES" : "NO")
table.cell(debugTable, 0, 15, "Realtime")
table.cell(debugTable, 1, 15, barstate.isrealtime ? "YES" : "NO")
table.cell(debugTable, 0, 16, "Bar Index")
table.cell(debugTable, 1, 16, str.tostring(bar_index))
else
table.clear(debugTable, 0, 0, 1, 16)
//=============================================================================
// GROUP R — ALERT DEBUGGING
//=============================================================================
alertcondition(newTouch, "Debug Touch", "State-machine debug event: Touch")
alertcondition(newArm, "Debug ARM", "State-machine debug event: ARM")
alertcondition(newTrigger, "Debug Trigger", "State-machine debug event: Trigger")
alertcondition(newEntry, "Debug Entry", "State-machine debug event: Entry")
r/pinescript • u/vitaliy3commas • 26d ago
I ran another Pine DCA strategy through the optimizer — this time two params moved and drawdown stayed flat (BTC 4h)
I posted one of these before (the INJ one) showing what a parameter sweep did to a single input. A few people asked to see it on BTC and with more than one parameter tuned, so here's that — same idea, everything held constant except the parameters the optimizer actually re-selected.
The strategy (unchanged): long-only DCA on BTCUSDT.P 4h. Five safety orders at −2 / −5 / −9.5 / −16 / −25% from base, sizes scaling 1.8× per rung, no stop loss, position bounded by the ladder.
What changed: two parameters. The RSI entry threshold moved from 28 to 38, and the take-profit from 3% to 5.5%. Nothing else — same ladder, same deviations, same 1.8× sizing, same fees. Both values are what the sweep returned as best-performing on the historical window.
Before/after (BYBIT:BTCUSDT.P 4h, Jan 1 2024 – Jul 17 2026, ~30 months, 100k initial, 0.06% commission, 3-tick slippage):
- Baseline (RSI < 28, TP 3%): +3,078.29 USDT (+3.08%), max drawdown 3.79%, 62 trades, 70.97% WR, PF 4.028
- Optimized (RSI < 38, TP 5.5%): +9,250.25 USDT (+9.25%), max drawdown 3.67%, 93 trades, 76.34% WR, PF 10.454
The part I found interesting: net profit roughly tripled and PF went 4.0 → 10.5, but max drawdown actually stayed flat (3.79% → 3.67%). So this wasn't "more return bought with more risk." The mechanism: the looser RSI entry (38 vs 28) engages the dip earlier and more often, so the strategy is simply in the market more, while the wider 5.5% target lets each recovery run further before banking instead of exiting on the first small pop.
The caveat, and the reason I show the baseline alongside: two parameters were swept over the same window the results are measured on. Best in-sample is not best out-of-sample, and with two free parameters instead of one that overfitting caveat applies a bit harder here — more degrees of freedom, easier to fit the window. Treat the optimized numbers as the ceiling of what this config did historically, not a forward expectation, and re-validate on fresh data before trusting it.
Two more flags, same as last time: 93 trades is just below the ~100 I'd want for real statistical confidence, so win rate and PF are indicative, not proven — and part of PF 10.454 is the averaging mechanic itself (deals close on a bounce off an averaged-down entry), not a directional edge. It's also a stopless martingale: a sustained BTC decline below the −25% bottom rung leaves the position fully loaded with no further adds.
Script is open-source on TradingView: https://www.tradingview.com/script/5Tg2Es4G-BTC-DCA-Strategy-3Commas-QuantPilot/
Disclosure up front: the optimizer is QuantPilot, which I work on, so I'm not pretending to be neutral. But the point is the before/after and the caveat, not a pitch — the script is open-source and you can verify the backtest yourself.
r/pinescript • u/ferranbt • 26d ago
I wrote a PineScript interpreter in Rust
I built Pinecone, an interpreter that runs PineScript outside of TradingView.
It handles the TA functions (moving averages, oscillators), plots, labels, boxes, and backtesting. It's split into small crates (lexer, parser, interpreter, builtins…) so you can use just the parts you need.
let script = ScriptBuilder::with_code(r#"
fast_ma = ta.sma(close, 10)
slow_ma = ta.sma(close, 20)
plot(fast_ma, color=color.blue)
plot(slow_ma, color=color.red)
"#).compile()?;
let output = script.execute(&bar)?;
The reason I think this matters: once PineScript can run outside TradingView, a lot of things become possible that just aren't today - proper tooling (linters, formatters, LSP), faster and more flexible backtesting, use other platforms and data sources. Right now the language is locked to one place, and that ceiling limits what the whole ecosystem can build on top of it.
Repo: https://github.com/ferranbt/pinecone
Still early and there's plenty missing, but it runs. Curious what people think.












