Code: Select all
//@version=5
strategy("Automated Trade Journal Pro", overlay=true, calc_on_every_tick=false, pyramiding=0)
// =========================================================================
// 1. JOURNAL INPUTS & SETTINGS
// =========================================================================
grp1 = "Journal Metadata"
setupType = input.string("VWAP Reversion", title="Setup Type / Strategy", group=grp1)
sendWebhook = input.bool(true, title="Send JSON Webhook on Close?", group=grp1)
// =========================================================================
// 2. DUMMY STRATEGY LOGIC (Replace with your actual entry/exit conditions)
// =========================================================================
fastMa = ta.sma(close, 9)
slowMa = ta.sma(close, 21)
longCond = ta.crossover(fastMa, slowMa)
shortCond = ta.crossunder(fastMa, slowMa)
// We use variables to lock in the exact Risk per trade for accurate R:R tracking
var float active_sl = na
var float active_risk = na
if (longCond and strategy.position_size == 0)
active_sl := low - ta.atr(14)
active_risk := close - active_sl
strategy.entry("Long", strategy.long)
strategy.exit("Exit Long", "Long", stop=active_sl, limit=close + (active_risk * 2))
if (shortCond and strategy.position_size == 0)
active_sl := high + ta.atr(14)
active_risk := active_sl - close
strategy.entry("Short", strategy.short)
strategy.exit("Exit Short", "Short", stop=active_sl, limit=close - (active_risk * 2))
// =========================================================================
// 3. AUTOMATED JOURNALING CORE
// =========================================================================
// Arrays to track data not natively stored by TradingView's strategy tester
var sl_history = array.new_float()
var risk_history = array.new_float()
var setup_history = array.new_string()
// Log the specific metrics at the exact moment the trade opens
if (strategy.opentrades > strategy.opentrades[1])
array.push(sl_history, active_sl)
array.push(risk_history, active_risk)
array.push(setup_history, setupType)
var int closed_trades_count = 0
// Trigger when a trade fully closes
if strategy.closedtrades > closed_trades_count
trades_to_process = strategy.closedtrades - closed_trades_count
for i = 0 to trades_to_process - 1
idx = strategy.closedtrades - 1 - i
// 1. Extract Core Native Data
t_entry_time = strategy.closedtrades.entry_time(idx)
t_pair = syminfo.tickerid
t_entry_price = strategy.closedtrades.entry_price(idx)
t_exit_price = strategy.closedtrades.exit_price(idx)
t_size = strategy.closedtrades.size(idx)
t_profit = strategy.closedtrades.profit(idx)
// 2. Extract Custom Data (from our arrays)
t_sl = array.size(sl_history) > idx ? array.get(sl_history, idx) : na
t_risk = array.size(risk_history) > idx ? array.get(risk_history, idx) : na
t_setup = array.size(setup_history) > idx ? array.get(setup_history, idx) : "Unknown"
// 3. Calculate Categorized Fields
t_outcome = t_profit > 0 ? "Win" : t_profit < 0 ? "Loss" : "Breakeven"
// Calculate Realized Reward-to-Risk (R:R)
total_risk_dollar = t_risk * t_size
realized_rr = total_risk_dollar > 0 ? (t_profit / total_risk_dollar) : 0.0
// 4. Generate the JSON Payload for Webhooks
if sendWebhook
json_payload = '{' +
'"Date": "' + str.format("{0,date,yyyy-MM-dd HH:mm}", t_entry_time) + '",' +
'"Pair": "' + t_pair + '",' +
'"Setup": "' + t_setup + '",' +
'"Outcome": "' + t_outcome + '",' +
'"Entry": ' + str.tostring(t_entry_price) + ',' +
'"Exit": ' + str.tostring(t_exit_price) + ',' +
'"StopLoss": ' + str.tostring(t_sl) + ',' +
'"Size": ' + str.tostring(t_size) + ',' +
'"RR": ' + str.tostring(realized_rr, "#.##") +
'}'
// Fire the alert containing the JSON data
alert(json_payload, alert.freq_once_per_bar_close)
closed_trades_count := strategy.closedtrades
// =========================================================================
// 4. ON-CHART VISUAL DASHBOARD
// =========================================================================
var table journal_tb = table.new(position.bottom_right, 9, 6, bgcolor=color.rgb(17, 17, 17, 10), border_width=1, border_color=color.gray)
if barstate.islast
// Create Headers
table.cell(journal_tb, 0, 0, "Date", text_color=color.white, bgcolor=color.gray)
table.cell(journal_tb, 1, 0, "Pair", text_color=color.white, bgcolor=color.gray)
table.cell(journal_tb, 2, 0, "Setup", text_color=color.white, bgcolor=color.gray)
table.cell(journal_tb, 3, 0, "Outcome", text_color=color.white, bgcolor=color.gray)
table.cell(journal_tb, 4, 0, "Entry", text_color=color.white, bgcolor=color.gray)
table.cell(journal_tb, 5, 0, "Exit", text_color=color.white, bgcolor=color.gray)
table.cell(journal_tb, 6, 0, "SL", text_color=color.white, bgcolor=color.gray)
table.cell(journal_tb, 7, 0, "Size", text_color=color.white, bgcolor=color.gray)
table.cell(journal_tb, 8, 0, "R:R", text_color=color.white, bgcolor=color.gray)
// Populate the last 5 trades
total_trades = strategy.closedtrades
loop_limit = math.min(total_trades, 5)
if loop_limit > 0
for i = 0 to loop_limit - 1
idx = total_trades - 1 - i
row = i + 1
// Re-fetch required table data
pft = strategy.closedtrades.profit(idx)
outc = pft > 0 ? "Win" : pft < 0 ? "Loss" : "BE"
row_col = pft > 0 ? color.new(color.green, 70) : pft < 0 ? color.new(color.red, 70) : color.new(color.gray, 70)
risk_val = array.size(risk_history) > idx ? array.get(risk_history, idx) : na
r_rr = (risk_val * strategy.closedtrades.size(idx)) > 0 ? (pft / (risk_val * strategy.closedtrades.size(idx))) : 0.0
table.cell(journal_tb, 0, row, str.format("{0,date,MM/dd HH:mm}", strategy.closedtrades.entry_time(idx)), text_color=color.white, bgcolor=row_col)
table.cell(journal_tb, 1, row, syminfo.ticker, text_color=color.white, bgcolor=row_col)
table.cell(journal_tb, 2, row, array.size(setup_history) > idx ? array.get(setup_history, idx) : "-", text_color=color.white, bgcolor=row_col)
table.cell(journal_tb, 3, row, outc, text_color=color.white, bgcolor=row_col)
table.cell(journal_tb, 4, row, str.tostring(strategy.closedtrades.entry_price(idx), format.mintick), text_color=color.white, bgcolor=row_col)
table.cell(journal_tb, 5, row, str.tostring(strategy.closedtrades.exit_price(idx), format.mintick), text_color=color.white, bgcolor=row_col)
table.cell(journal_tb, 6, row, str.tostring(array.size(sl_history) > idx ? array.get(sl_history, idx) : na, format.mintick), text_color=color.white, bgcolor=row_col)
table.cell(journal_tb, 7, row, str.tostring(strategy.closedtrades.size(idx)), text_color=color.white, bgcolor=row_col)
table.cell(journal_tb, 8, row, str.tostring(r_rr, "#.##") + "R", text_color=color.white, bgcolor=row_col)