Pinaコード(5分足)

nakasato

もしくは、以下をコピーしてお使いください。

//@version=5
indicator("TSUBAKI 5M S1.0 チャート表示サインEA版", shorttitle="TSUBAKI 5M EA", overlay=false, max_labels_count=500, max_lines_count=500)

// =====================================================
// TSUBAKI 5M 専用
// ・5分足をメインに、チャート上に実際に表示されたサインだけ通知
// ・TradingViewのWebhook URLは http://128.22.126.239/all-sign-live を使用
// ・アラート条件は「Any alert() function call」を選択
// ・AIがチャート外のエントリーを作る仕様ではありません
// ・TP/SL通知は結果通知・AI学習用。新規発注対象ではない
// =====================================================

// =====================================================
// Webhook / Discord設定
// =====================================================
secretKey = input.string("CHANGE_ME_SECRET", "Webhook認証キー", display=display.none)
systemName = input.string("TSUBAKI_5M_CHART_SIGNAL_EA", "システム名", display=display.none)
strategyName = input.string("TSUBAKI_5M_CHART_SIGNAL", "サーバー集計用strategy", display=display.none)
sourceName = input.string("chart_signal", "通知ソース", display=display.none)

sendEntryAlert = input.bool(true, "ENTRYアラート送信", display=display.none)
sendExitAlert = input.bool(true, "TP/SLアラート送信(EA学習用ON)", display=display.none)

// =====================================================
// 基本設定
// =====================================================
rciLen = input.int(9, "RCI期間", minval=2, display=display.none)

tfFast = input.timeframe("1", "短期足(1分)", display=display.none)
tfMain = input.timeframe("5", "メイン足(5分)", display=display.none)
tfTrend = input.timeframe("15", "方向確認足(15分)", display=display.none)

useLong = input.bool(true, "LONGサインを使う", display=display.none)
useShort = input.bool(true, "SHORTサインを使う", display=display.none)

// =====================================================
// 採用設定
// =====================================================
signalMode = input.string("標準", "サイン感度", options=["多め", "標準", "少なめ"], display=display.none)

longRciZone = input.int(-50, "LONG反転RCI水準", minval=-100, maxval=0, display=display.none)
shortRciZone = input.int(50, "SHORT反転RCI水準", minval=0, maxval=100, display=display.none)

useTrendFilter = input.bool(true, "15分方向フィルター", display=display.none)
useEmaFilter = input.bool(true, "EMA位置フィルター", display=display.none)
useCandleFilter = input.bool(true, "ローソク足方向フィルター", display=display.none)

cooldownBarsMany = input.int(3, "クールダウン:多め", minval=0, display=display.none)
cooldownBarsNormal = input.int(6, "クールダウン:標準", minval=0, display=display.none)
cooldownBarsFew = input.int(10, "クールダウン:少なめ", minval=0, display=display.none)

cooldownBars = signalMode == "多め" ? cooldownBarsMany : signalMode == "標準" ? cooldownBarsNormal : cooldownBarsFew

// =====================================================
// EMA / ATR / TP SL
// =====================================================
emaFastLen = input.int(20, "EMA短期", display=display.none)
emaMidLen = input.int(75, "EMA中期", display=display.none)
emaSlowLen = input.int(200, "EMA長期", display=display.none)

atrLen = input.int(14, "ATR期間", display=display.none)

swingLookback = input.int(6, "SL用直近高安値本数", minval=2, maxval=50, display=display.none)
slBufferAtr = input.float(0.22, "SLバッファATR倍率", minval=0.0, maxval=3.0, step=0.01, display=display.none)

tpRR = input.float(0.55, "TP RR", minval=0.1, maxval=3.0, step=0.05, display=display.none)

useMinRiskFilter = input.bool(true, "小さすぎる損切り幅を除外", display=display.none)
minRiskAtr = input.float(0.30, "最低リスクATR倍率", minval=0.05, maxval=3.0, step=0.01, display=display.none)

useMaxRiskFilter = input.bool(true, "大きすぎる損切り幅を除外", display=display.none)
maxRiskAtr = input.float(1.5, "最大リスクATR倍率", minval=0.2, maxval=5.0, step=0.1, display=display.none)

// =====================================================
// 表示設定
// =====================================================
showFastRci = input.bool(true, "1分RCI表示", display=display.none)
showMainRci = input.bool(true, "5分RCI表示", display=display.none)
showTrendRci = input.bool(false, "15分RCI表示", display=display.none)

showChartEntry = input.bool(true, "価格チャートにENTRY表示", display=display.none)
showResultMarker = input.bool(true, "TP/SL到達表示", display=display.none)
showPanelSignal = input.bool(true, "下段に三角サイン表示", display=display.none)

showEntryPrice = input.bool(false, "ENTRY価格表示", display=display.none)
showResultPrice = input.bool(false, "TP/SL価格表示", display=display.none)

showBg = input.bool(true, "サイン背景ハイライト", display=display.none)
showTable = input.bool(false, "勝率パネル表示", display=display.none)

showEmaOnChart = input.bool(true, "価格チャートにEMA表示", display=display.none)
showEma20 = input.bool(true, "EMA20表示", display=display.none)
showEma75 = input.bool(true, "EMA75表示", display=display.none)
showEma200 = input.bool(false, "EMA200表示", display=display.none)

resultMode = input.string("保守的:SL優先", "同一足でTP/SL両方到達時", options=["保守的:SL優先", "楽観的:TP優先"], display=display.none)

// =====================================================
// RCI関数
// =====================================================
rci(src, len) =>
    d = 0.0
    for i = 0 to len - 1
        rank_price = 0
        rank_time = len - i
        for j = 0 to len - 1
            if src[j] < src[i]
                rank_price += 1
        d += math.pow(rank_time - (rank_price + 1), 2)
    1 - 6 * d / (len * (math.pow(len, 2) - 1))

// =====================================================
// MTF取得
// =====================================================
fastOpen = request.security(syminfo.tickerid, tfFast, open, barmerge.gaps_off, barmerge.lookahead_off)
fastHigh = request.security(syminfo.tickerid, tfFast, high, barmerge.gaps_off, barmerge.lookahead_off)
fastLow = request.security(syminfo.tickerid, tfFast, low, barmerge.gaps_off, barmerge.lookahead_off)
fastClose = request.security(syminfo.tickerid, tfFast, close, barmerge.gaps_off, barmerge.lookahead_off)
fastRci = request.security(syminfo.tickerid, tfFast, rci(close, rciLen) * 100, barmerge.gaps_off, barmerge.lookahead_off)

mainOpen = request.security(syminfo.tickerid, tfMain, open, barmerge.gaps_off, barmerge.lookahead_off)
mainHigh = request.security(syminfo.tickerid, tfMain, high, barmerge.gaps_off, barmerge.lookahead_off)
mainLow = request.security(syminfo.tickerid, tfMain, low, barmerge.gaps_off, barmerge.lookahead_off)
mainClose = request.security(syminfo.tickerid, tfMain, close, barmerge.gaps_off, barmerge.lookahead_off)

mainRci = request.security(syminfo.tickerid, tfMain, rci(close, rciLen) * 100, barmerge.gaps_off, barmerge.lookahead_off)
mainAtr = request.security(syminfo.tickerid, tfMain, ta.atr(atrLen), barmerge.gaps_off, barmerge.lookahead_off)

mainEma20 = request.security(syminfo.tickerid, tfMain, ta.ema(close, emaFastLen), barmerge.gaps_off, barmerge.lookahead_off)
mainEma75 = request.security(syminfo.tickerid, tfMain, ta.ema(close, emaMidLen), barmerge.gaps_off, barmerge.lookahead_off)
mainEma200 = request.security(syminfo.tickerid, tfMain, ta.ema(close, emaSlowLen), barmerge.gaps_off, barmerge.lookahead_off)
mainEma20Past = request.security(syminfo.tickerid, tfMain, ta.ema(close, emaFastLen)[2], barmerge.gaps_off, barmerge.lookahead_off)

trendClose = request.security(syminfo.tickerid, tfTrend, close, barmerge.gaps_off, barmerge.lookahead_off)
trendRci = request.security(syminfo.tickerid, tfTrend, rci(close, rciLen) * 100, barmerge.gaps_off, barmerge.lookahead_off)
trendEma20 = request.security(syminfo.tickerid, tfTrend, ta.ema(close, emaFastLen), barmerge.gaps_off, barmerge.lookahead_off)
trendEma75 = request.security(syminfo.tickerid, tfTrend, ta.ema(close, emaMidLen), barmerge.gaps_off, barmerge.lookahead_off)

// =====================================================
// 方向判定
// =====================================================
trendUp = trendClose > trendEma75 and trendEma20 >= trendEma75
trendDown = trendClose < trendEma75 and trendEma20 <= trendEma75

mainUp = mainClose > mainEma75
mainDown = mainClose < mainEma75

mainEmaSlopeUp = mainEma20 > mainEma20Past
mainEmaSlopeDown = mainEma20 < mainEma20Past

fastBull = fastClose > fastOpen
fastBear = fastClose < fastOpen

mainBull = mainClose > mainOpen
mainBear = mainClose < mainOpen

// =====================================================
// RCI反転
// =====================================================
fastRising = fastRci > fastRci[1]
fastFalling = fastRci < fastRci[1]

mainRising = mainRci > mainRci[1]
mainFalling = mainRci < mainRci[1]

fastLongTurn = fastRci <= longRciZone and fastRising
fastShortTurn = fastRci >= shortRciZone and fastFalling

mainLongTurn = mainRci <= longRciZone and mainRising
mainShortTurn = mainRci >= shortRciZone and mainFalling

fastLongCross = ta.crossover(fastRci, -30)
fastShortCross = ta.crossunder(fastRci, 30)

mainLongCross = ta.crossover(mainRci, -30)
mainShortCross = ta.crossunder(mainRci, 30)

// =====================================================
// EMA付近
// =====================================================
emaDistance = math.abs(mainClose - mainEma20)
nearEma20 = emaDistance <= mainAtr * 0.45

longEmaOk = not useEmaFilter or mainClose >= mainEma20 or nearEma20
shortEmaOk = not useEmaFilter or mainClose <= mainEma20 or nearEma20

longCandleOk = not useCandleFilter or fastBull or mainBull
shortCandleOk = not useCandleFilter or fastBear or mainBear

longTrendOk = not useTrendFilter or trendUp or mainUp
shortTrendOk = not useTrendFilter or trendDown or mainDown

// =====================================================
// 5分足チャートサインエンジン
// =====================================================
longEngineA = longTrendOk and longEmaOk and longCandleOk and (fastLongTurn or fastLongCross) and mainRising
shortEngineA = shortTrendOk and shortEmaOk and shortCandleOk and (fastShortTurn or fastShortCross) and mainFalling

longEngineB = (not useTrendFilter or not trendDown) and longEmaOk and longCandleOk and mainLongTurn and fastRising
shortEngineB = (not useTrendFilter or not trendUp) and shortEmaOk and shortCandleOk and mainShortTurn and fastFalling

longEngineC = mainUp and mainEmaSlopeUp and nearEma20 and fastRising and fastBull
shortEngineC = mainDown and mainEmaSlopeDown and nearEma20 and fastFalling and fastBear

rawLongSignal = useLong and (longEngineA or longEngineB or longEngineC)
rawShortSignal = useShort and (shortEngineA or shortEngineB or shortEngineC)

// =====================================================
// スコア
// =====================================================
longScore = 0
shortScore = 0

longScore += trendUp ? 2 : 0
shortScore += trendDown ? 2 : 0

longScore += mainUp ? 1 : 0
shortScore += mainDown ? 1 : 0

longScore += mainEmaSlopeUp ? 1 : 0
shortScore += mainEmaSlopeDown ? 1 : 0

longScore += fastLongTurn ? 2 : 0
shortScore += fastShortTurn ? 2 : 0

longScore += mainLongTurn ? 2 : 0
shortScore += mainShortTurn ? 2 : 0

longScore += fastBull ? 1 : 0
shortScore += fastBear ? 1 : 0

longScore += nearEma20 ? 1 : 0
shortScore += nearEma20 ? 1 : 0

longScore += longEngineA ? 2 : 0
shortScore += shortEngineA ? 2 : 0

longScore += longEngineB ? 1 : 0
shortScore += shortEngineB ? 1 : 0

longScore += longEngineC ? 1 : 0
shortScore += shortEngineC ? 1 : 0

scoreMin = signalMode == "多め" ? 4 : signalMode == "標準" ? 5 : 6

// =====================================================
// クールダウン
// =====================================================
var int lastSignalBar = na
cooldownOk = na(lastSignalBar) or bar_index - lastSignalBar > cooldownBars

// =====================================================
// SL / TP
// =====================================================
swingLow = request.security(syminfo.tickerid, tfMain, ta.lowest(low, swingLookback), barmerge.gaps_off, barmerge.lookahead_off)
swingHigh = request.security(syminfo.tickerid, tfMain, ta.highest(high, swingLookback), barmerge.gaps_off, barmerge.lookahead_off)

longSl = swingLow - mainAtr * slBufferAtr
shortSl = swingHigh + mainAtr * slBufferAtr

longRisk = mainClose - longSl
shortRisk = shortSl - mainClose

longTp = mainClose + longRisk * tpRR
shortTp = mainClose - shortRisk * tpRR

longRiskOk = longRisk > syminfo.mintick and (not useMinRiskFilter or longRisk >= mainAtr * minRiskAtr) and (not useMaxRiskFilter or longRisk <= mainAtr * maxRiskAtr)
shortRiskOk = shortRisk > syminfo.mintick and (not useMinRiskFilter or shortRisk >= mainAtr * minRiskAtr) and (not useMaxRiskFilter or shortRisk <= mainAtr * maxRiskAtr)

// =====================================================
// 仮想ポジション管理
// =====================================================
var bool virtualActive = false
var string virtualSide = "NONE"
var float virtualEntry = na
var float virtualSl = na
var float virtualTp = na
var int virtualEntryBar = na
var int virtualScore = 0

// =====================================================
// ENTRYとTP/SLを点線で結ぶための保持変数
// =====================================================
var int activeEntryBarIndex = na
var float activeEntryPriceForLine = na
var string activeEntrySideForLine = "NONE"

// =====================================================
// 勝率カウント
// =====================================================
var int totalTrades = 0
var int winTrades = 0
var int lossTrades = 0

var int longTrades = 0
var int longWins = 0
var int longLosses = 0

var int shortTrades = 0
var int shortWins = 0
var int shortLosses = 0

var int currentWinStreak = 0
var int currentLossStreak = 0
var int maxWinStreak = 0
var int maxLossStreak = 0

var string lastResult = "なし"

winRate = totalTrades > 0 ? winTrades * 100.0 / totalTrades : na
longWinRate = longTrades > 0 ? longWins * 100.0 / longTrades : na
shortWinRate = shortTrades > 0 ? shortWins * 100.0 / shortTrades : na

// =====================================================
// 最終サイン
// =====================================================
canEnter = not virtualActive

longSignal = barstate.isconfirmed and canEnter and cooldownOk and rawLongSignal and longScore >= scoreMin and longRiskOk
shortSignal = barstate.isconfirmed and canEnter and cooldownOk and rawShortSignal and shortScore >= scoreMin and shortRiskOk

finalLong = longSignal and not shortSignal or longSignal and shortSignal and longScore >= shortScore
finalShort = shortSignal and not longSignal or longSignal and shortSignal and shortScore > longScore

// =====================================================
// TP / SL判定
// =====================================================
longTpHit = virtualActive and virtualSide == "LONG" and high >= virtualTp
longSlHit = virtualActive and virtualSide == "LONG" and low <= virtualSl

shortTpHit = virtualActive and virtualSide == "SHORT" and low <= virtualTp
shortSlHit = virtualActive and virtualSide == "SHORT" and high >= virtualSl

longExitTp = virtualActive and virtualSide == "LONG" and bar_index > virtualEntryBar and (resultMode == "楽観的:TP優先" ? longTpHit : longTpHit and not longSlHit)
longExitSl = virtualActive and virtualSide == "LONG" and bar_index > virtualEntryBar and (resultMode == "保守的:SL優先" ? longSlHit : longSlHit and not longTpHit)

shortExitTp = virtualActive and virtualSide == "SHORT" and bar_index > virtualEntryBar and (resultMode == "楽観的:TP優先" ? shortTpHit : shortTpHit and not shortSlHit)
shortExitSl = virtualActive and virtualSide == "SHORT" and bar_index > virtualEntryBar and (resultMode == "保守的:SL優先" ? shortSlHit : shortSlHit and not shortTpHit)

// =====================================================
// JSON作成
// =====================================================
makeJson(eventType, side, resultText, score, entryPrice, slPrice, tpPrice, exitPrice, exitReason) =>
    riskValue = math.abs(entryPrice - slPrice)
    rewardValue = math.abs(tpPrice - entryPrice)
    actualRR = riskValue > 0 ? rewardValue / riskValue : na

    string json = "{"
    json := json + "\"secret\":\"" + secretKey + "\","
    json := json + "\"system\":\"" + systemName + "\","
    json := json + "\"strategy\":\"" + strategyName + "\","
    json := json + "\"source\":\"" + sourceName + "\","
    json := json + "\"version\":\"S1.3\","
    json := json + "\"operation_mode\":\"chart_display_signal_ea\","
    json := json + "\"event_type\":\"" + eventType + "\","
    json := json + "\"event_id\":\"" + syminfo.ticker + "_" + str.tostring(time) + "_chart_" + side + "_" + resultText + "\","
    json := json + "\"symbol\":\"" + syminfo.ticker + "\","
    json := json + "\"tickerid\":\"" + syminfo.tickerid + "\","
    json := json + "\"bar_time\":" + str.tostring(time) + ","
    json := json + "\"bar_index\":" + str.tostring(bar_index) + ","
    json := json + "\"timeframe_chart\":\"" + timeframe.period + "\","
    json := json + "\"timeframe\":\"" + tfMain + "\","
    json := json + "\"tf_fast\":\"" + tfFast + "\","
    json := json + "\"tf_main\":\"" + tfMain + "\","
    json := json + "\"tf_trend\":\"" + tfTrend + "\","
    json := json + "\"side\":\"" + side + "\","
    json := json + "\"engine\":\"chart_display_signal\","
    json := json + "\"tier\":\"" + resultText + "\","
    json := json + "\"score\":" + str.tostring(score) + ","
    json := json + "\"entry\":" + str.tostring(entryPrice) + ","
    json := json + "\"sl\":" + str.tostring(slPrice) + ","
    json := json + "\"tp\":" + str.tostring(tpPrice) + ","
    json := json + "\"exit_price\":" + str.tostring(exitPrice) + ","
    json := json + "\"exit_reason\":\"" + exitReason + "\","
    json := json + "\"result\":\"" + resultText + "\","
    json := json + "\"risk\":" + str.tostring(riskValue) + ","
    json := json + "\"reward\":" + str.tostring(rewardValue) + ","
    json := json + "\"actual_rr\":" + str.tostring(actualRR) + ","
    json := json + "\"tp_rr_setting\":" + str.tostring(tpRR) + ","
    json := json + "\"rci_fast\":" + str.tostring(fastRci) + ","
    json := json + "\"rci_main\":" + str.tostring(mainRci) + ","
    json := json + "\"rci_trend\":" + str.tostring(trendRci) + ","
    json := json + "\"trend_up\":" + str.tostring(trendUp) + ","
    json := json + "\"trend_down\":" + str.tostring(trendDown) + ","
    json := json + "\"main_up\":" + str.tostring(mainUp) + ","
    json := json + "\"main_down\":" + str.tostring(mainDown) + ","
    json := json + "\"near_ema20\":" + str.tostring(nearEma20) + ","
    json := json + "\"win_rate\":" + str.tostring(winRate) + ","
    json := json + "\"total_trades\":" + str.tostring(totalTrades) + ","
    json := json + "\"wins\":" + str.tostring(winTrades) + ","
    json := json + "\"losses\":" + str.tostring(lossTrades)
    json := json + "}"
    json

// =====================================================
// TradingView通知文作成(5分足チャート表示サインEA用)
// Python側が読み取れるJSON直送形式に固定
// ENTRY通知だけを発注対象にする想定。チャートに出たfinalLong/finalShortのみ通知
// TP/SL通知は結果通知・AI学習用。Python Bot側では新規発注しない
// =====================================================
makeTvMessage(side, resultText, entryPrice, slPrice, tpPrice, jsonText) =>
    // TradingView → 中継サーバー(main_full_v2.py)へJSONを直接送る
    // Discord用の文章はサーバー側でAI判定・DB保存・勝率集計後に生成する
    jsonText

drawResultLine(entryBar, entryPrice, exitBar, exitPrice, isTp) =>
    line.new(x1=entryBar, y1=entryPrice, x2=exitBar, y2=exitPrice, xloc=xloc.bar_index, extend=extend.none, color=isTp ? color.new(color.lime, 0) : color.new(color.red, 0), style=line.style_dotted, width=2, force_overlay=true)

// =====================================================
// TP / SL到達
// =====================================================
if longExitTp
    if not na(activeEntryBarIndex) and not na(activeEntryPriceForLine)
        drawResultLine(activeEntryBarIndex, activeEntryPriceForLine, bar_index, virtualTp, true)

    if showResultMarker
        label.new(bar_index, high, showResultPrice ? "TP\n" + str.tostring(virtualTp, format.mintick) : "TP", style=label.style_label_down, textcolor=color.white, color=color.new(color.lime, 0), size=size.tiny, force_overlay=true)

    winTrades += 1
    longWins += 1
    currentWinStreak += 1
    currentLossStreak := 0
    maxWinStreak := math.max(maxWinStreak, currentWinStreak)
    lastResult := "LONG 勝ち"

    if sendExitAlert
        jsonLongTp = makeJson("notify", "LONG", "TP", virtualScore, virtualEntry, virtualSl, virtualTp, virtualTp, "take_profit")
        alert(makeTvMessage("LONG", "TP", virtualEntry, virtualSl, virtualTp, jsonLongTp), alert.freq_once_per_bar_close)

    virtualActive := false
    virtualSide := "NONE"
    activeEntryBarIndex := na
    activeEntryPriceForLine := na
    activeEntrySideForLine := "NONE"

if longExitSl
    if not na(activeEntryBarIndex) and not na(activeEntryPriceForLine)
        drawResultLine(activeEntryBarIndex, activeEntryPriceForLine, bar_index, virtualSl, false)

    if showResultMarker
        label.new(bar_index, low, showResultPrice ? "SL\n" + str.tostring(virtualSl, format.mintick) : "SL", style=label.style_label_up, textcolor=color.white, color=color.new(color.red, 0), size=size.tiny, force_overlay=true)

    lossTrades += 1
    longLosses += 1
    currentLossStreak += 1
    currentWinStreak := 0
    maxLossStreak := math.max(maxLossStreak, currentLossStreak)
    lastResult := "LONG 負け"

    if sendExitAlert
        jsonLongSl = makeJson("notify", "LONG", "SL", virtualScore, virtualEntry, virtualSl, virtualTp, virtualSl, "stop_loss")
        alert(makeTvMessage("LONG", "SL", virtualEntry, virtualSl, virtualTp, jsonLongSl), alert.freq_once_per_bar_close)

    virtualActive := false
    virtualSide := "NONE"

if shortExitTp
    if not na(activeEntryBarIndex) and not na(activeEntryPriceForLine)
        drawResultLine(activeEntryBarIndex, activeEntryPriceForLine, bar_index, virtualTp, true)

    if showResultMarker
        label.new(bar_index, low, showResultPrice ? "TP\n" + str.tostring(virtualTp, format.mintick) : "TP", style=label.style_label_up, textcolor=color.white, color=color.new(color.lime, 0), size=size.tiny, force_overlay=true)

    winTrades += 1
    shortWins += 1
    currentWinStreak += 1
    currentLossStreak := 0
    maxWinStreak := math.max(maxWinStreak, currentWinStreak)
    lastResult := "SHORT 勝ち"

    if sendExitAlert
        jsonShortTp = makeJson("notify", "SHORT", "TP", virtualScore, virtualEntry, virtualSl, virtualTp, virtualTp, "take_profit")
        alert(makeTvMessage("SHORT", "TP", virtualEntry, virtualSl, virtualTp, jsonShortTp), alert.freq_once_per_bar_close)

    virtualActive := false
    virtualSide := "NONE"

if shortExitSl
    if not na(activeEntryBarIndex) and not na(activeEntryPriceForLine)
        drawResultLine(activeEntryBarIndex, activeEntryPriceForLine, bar_index, virtualSl, false)

    if showResultMarker
        label.new(bar_index, high, showResultPrice ? "SL\n" + str.tostring(virtualSl, format.mintick) : "SL", style=label.style_label_down, textcolor=color.white, color=color.new(color.red, 0), size=size.tiny, force_overlay=true)

    lossTrades += 1
    shortLosses += 1
    currentLossStreak += 1
    currentWinStreak := 0
    maxLossStreak := math.max(maxLossStreak, currentLossStreak)
    lastResult := "SHORT 負け"

    if sendExitAlert
        jsonShortSl = makeJson("notify", "SHORT", "SL", virtualScore, virtualEntry, virtualSl, virtualTp, virtualSl, "stop_loss")
        alert(makeTvMessage("SHORT", "SL", virtualEntry, virtualSl, virtualTp, jsonShortSl), alert.freq_once_per_bar_close)

    virtualActive := false
    virtualSide := "NONE"

// =====================================================
// ENTRY
// finalLong / finalShort が成立し、チャートに表示されるサインだけ通知
// AI判断だけのチャート外エントリー通知は行わない
// =====================================================
if finalLong
    if showChartEntry
        label.new(bar_index, mainClose, showEntryPrice ? "LONG\n" + str.tostring(mainClose, format.mintick) : "LONG", style=label.style_label_up, textcolor=color.white, color=color.new(color.lime, 0), size=size.small, force_overlay=true)

    virtualActive := true
    virtualSide := "LONG"
    virtualEntry := mainClose
    virtualSl := longSl
    virtualTp := longTp
    virtualEntryBar := bar_index
    virtualScore := longScore
    activeEntryBarIndex := bar_index
    activeEntryPriceForLine := mainClose
    activeEntrySideForLine := "LONG"

    totalTrades += 1
    longTrades += 1
    lastSignalBar := bar_index

    if sendEntryAlert
        jsonLongEntry = makeJson("notify", "LONG", "ENTRY", longScore, mainClose, longSl, longTp, mainClose, "entry")
        alert(makeTvMessage("LONG", "ENTRY", mainClose, longSl, longTp, jsonLongEntry), alert.freq_once_per_bar_close)

if finalShort
    if showChartEntry
        label.new(bar_index, mainClose, showEntryPrice ? "SHORT\n" + str.tostring(mainClose, format.mintick) : "SHORT", style=label.style_label_down, textcolor=color.white, color=color.new(color.red, 0), size=size.small, force_overlay=true)

    virtualActive := true
    virtualSide := "SHORT"
    virtualEntry := mainClose
    virtualSl := shortSl
    virtualTp := shortTp
    virtualEntryBar := bar_index
    virtualScore := shortScore
    activeEntryBarIndex := bar_index
    activeEntryPriceForLine := mainClose
    activeEntrySideForLine := "SHORT"

    totalTrades += 1
    shortTrades += 1
    lastSignalBar := bar_index

    if sendEntryAlert
        jsonShortEntry = makeJson("notify", "SHORT", "ENTRY", shortScore, mainClose, shortSl, shortTp, mainClose, "entry")
        alert(makeTvMessage("SHORT", "ENTRY", mainClose, shortSl, shortTp, jsonShortEntry), alert.freq_once_per_bar_close)

// =====================================================
// 背景
// =====================================================
bgcolor(showBg and finalLong ? color.new(color.lime, 92) : na)
bgcolor(showBg and finalShort ? color.new(color.red, 92) : na)

// =====================================================
// 価格チャートEMA
// =====================================================
plot(showEmaOnChart and showEma20 ? mainEma20 : na, "EMA20", color=color.new(color.yellow, 0), linewidth=1, force_overlay=true, display=display.pane)
plot(showEmaOnChart and showEma75 ? mainEma75 : na, "EMA75", color=color.new(color.orange, 0), linewidth=2, force_overlay=true, display=display.pane)
plot(showEmaOnChart and showEma200 ? mainEma200 : na, "EMA200", color=color.new(color.purple, 0), linewidth=2, force_overlay=true, display=display.pane)

// =====================================================
// RCIパネル
// =====================================================
hline(0, "0", color=color.gray)
hline(60, "+60", color=color.new(color.red, 0), linestyle=hline.style_dashed)
hline(30, "+30", color=color.new(color.red, 40), linestyle=hline.style_dashed)
hline(-30, "-30", color=color.new(color.blue, 40), linestyle=hline.style_dashed)
hline(-60, "-60", color=color.new(color.blue, 0), linestyle=hline.style_dashed)
hline(80, "+80", color=color.gray, linestyle=hline.style_dotted)
hline(-80, "-80", color=color.gray, linestyle=hline.style_dotted)

plot(showFastRci ? fastRci : na, "1分RCI", color=color.new(color.aqua, 0), linewidth=1, display=display.pane)
plot(showMainRci ? mainRci : na, "5分RCI", color=color.new(color.blue, 0), linewidth=2, display=display.pane)
plot(showTrendRci ? trendRci : na, "15分RCI", color=color.new(color.yellow, 0), linewidth=1, display=display.pane)

longZoneTop = plot(-30, display=display.none)
longZoneBottom = plot(-60, display=display.none)
shortZoneTop = plot(60, display=display.none)
shortZoneBottom = plot(30, display=display.none)

fill(longZoneTop, longZoneBottom, color=color.new(color.blue, 88))
fill(shortZoneTop, shortZoneBottom, color=color.new(color.red, 88))

plotshape(showPanelSignal and finalLong, title="LONG", style=shape.triangleup, location=location.bottom, color=color.new(color.lime, 0), size=size.small)
plotshape(showPanelSignal and finalShort, title="SHORT", style=shape.triangledown, location=location.top, color=color.new(color.red, 0), size=size.small)

// =====================================================
// 勝率パネル:初期OFF
// =====================================================
var table t = table.new(position.top_right, 2, 12, border_width=1)

if showTable and barstate.islast
    table.cell(t, 0, 0, "TSUBAKI 5M", text_color=color.white, bgcolor=color.new(color.black, 0))
    table.cell(t, 1, 0, "S1.0", text_color=color.white, bgcolor=color.new(color.black, 0))

    table.cell(t, 0, 1, "総数", text_color=color.white)
    table.cell(t, 1, 1, str.tostring(totalTrades), text_color=color.white)

    table.cell(t, 0, 2, "勝ち / 負け", text_color=color.white)
    table.cell(t, 1, 2, str.tostring(winTrades) + " / " + str.tostring(lossTrades), text_color=color.white)

    table.cell(t, 0, 3, "勝率", text_color=color.white)
    table.cell(t, 1, 3, na(winRate) ? "計測中" : str.tostring(winRate, "#.0") + "%", text_color=color.white)

    table.cell(t, 0, 4, "LONG勝率", text_color=color.white)
    table.cell(t, 1, 4, na(longWinRate) ? "計測中" : str.tostring(longWinRate, "#.0") + "%", text_color=color.white)

    table.cell(t, 0, 5, "SHORT勝率", text_color=color.white)
    table.cell(t, 1, 5, na(shortWinRate) ? "計測中" : str.tostring(shortWinRate, "#.0") + "%", text_color=color.white)

    table.cell(t, 0, 6, "LONG数", text_color=color.white)
    table.cell(t, 1, 6, str.tostring(longTrades), text_color=color.white)

    table.cell(t, 0, 7, "SHORT数", text_color=color.white)
    table.cell(t, 1, 7, str.tostring(shortTrades), text_color=color.white)

    table.cell(t, 0, 8, "連勝 / 連敗", text_color=color.white)
    table.cell(t, 1, 8, str.tostring(currentWinStreak) + " / " + str.tostring(currentLossStreak), text_color=color.white)

    table.cell(t, 0, 9, "最大連勝/連敗", text_color=color.white)
    table.cell(t, 1, 9, str.tostring(maxWinStreak) + " / " + str.tostring(maxLossStreak), text_color=color.white)

    table.cell(t, 0, 10, "仮想ポジ", text_color=color.white)
    table.cell(t, 1, 10, virtualActive ? virtualSide : "なし", text_color=color.white)

    table.cell(t, 0, 11, "直近結果", text_color=color.white)
    table.cell(t, 1, 11, lastResult, text_color=color.white)
記事URLをコピーしました