
这不是又一个技术分析策略,而是基于比特币4年减半周期的长期投资框架。回测数据显示:严格按照减半时间节点执行买卖,单周期最高收益可达2000%以上。但别急着兴奋,这个策略需要极强的执行力和风险承受能力。
核心逻辑简单粗暴:减半时买入,40-80周后分批获利了结,135周后重新建仓。听起来容易,做起来需要钢铁般的意志力。
阶段一:减半买入期(0-40周) 减半事件发生后立即建仓,这是整个策略的核心入场点。历史数据显示,减半后40周内是最佳积累期,此时市场情绪通常还未完全反应供应减少的影响。
阶段二:获利了结期(40-80周) 减半后40-80周是历史上比特币价格爆发的黄金窗口。2016年减半后78周比特币涨幅超过3000%,2020年减半后类似。这个时间窗口不是猜测,是基于供需基本面的数学推导。
阶段三:熊市建仓期(135周后) 减半后135周通常进入深度熊市,此时启动DCA策略。这个时机选择优于盲目定投,因为避开了牛市高点的无效投入。
最大风险:执行力不足 策略最大敌人不是市场波动,而是人性。减半时买入需要在市场悲观时逆向操作,获利了结需要在狂欢中保持冷静。历史显示90%的人无法完整执行。
资金管理要求 建议单次投入不超过总资产的20%,因为单个周期可能面临80%以上回撤。2018年熊市从2万美元跌至3200美元,即使在”正确”时间买入也要承受巨大浮亏。
市场环境变化风险 策略基于历史3个完整周期数据,但比特币市场正在成熟化。机构资金涌入、ETF获批等因素可能改变传统周期规律。过往表现不代表未来收益,这不是空话。
40周获利起点:基于历史减半后供需平衡点计算,过早获利可能错过主升浪,过晚可能套在高点。
80周获利终点:历史数据显示减半后80周是价格见顶的高概率区间,此时必须开始分批减仓,不要贪恋最后一段涨幅。
135周DCA启动:熊市底部区域的统计学最优解,此时开始定投的风险收益比最佳。
这个策略适合有5年以上投资周期的资金,不适合急需用钱或风险承受能力低的投资者。单个周期需要承受2-3年的浮亏期,心理压力巨大。
策略胜率不在于预测短期价格,而在于把握长期供需周期。比特币减半是确定性事件,但价格反应的时间和幅度仍有不确定性。
重要提醒:这是高风险投资策略,存在本金全部亏损的可能。历史回测数据不保证未来收益,投资前请充分评估自身风险承受能力。
/*backtest
start: 2017-08-17 08:00:00
end: 2025-10-07 08:00:00
period: 1d
basePeriod: 1d
exchanges: [{"eid":"Binance","currency":"BTC_USDT","balance":500000}]
*/
//@version=6
strategy(title='Bitcoin Halving Cycle Profit - Backtesting', shorttitle='BTC Halv', overlay=true, default_qty_type=strategy.percent_of_equity, default_qty_value=100, initial_capital=10000, commission_type=strategy.commission.percent, commission_value=0.1)
// ════════════════════════════════════════════════════════════════════════════════════════════════
// CONFIGURATION & INPUTS
// ════════════════════════════════════════════════════════════════════════════════════════════════
// Backtesting Settings
enableBacktesting = input.bool(true, "Enable Backtesting", group="Backtesting Settings")
enableShortTrades = input.bool(true, "Enable Short Trades", group="Backtesting Settings")
positionSize = input.float(100, "Position Size (%)", minval=10, maxval=100, group="Backtesting Settings")
slippage = input.float(0.05, "Slippage (%)", minval=0, maxval=1, group="Backtesting Settings")
// Main Settings
showHalvingLines = input.bool(true, "Show Halving Lines", group="Display Options")
showProfitZones = input.bool(true, "Show Profit Zones", group="Display Options")
showBackgroundGradient = input.bool(true, "Show Background Gradient", group="Display Options")
showLabels = input.bool(true, "Show Labels", group="Display Options")
showDCAZone = input.bool(true, "Show DCA Zone", group="Display Options")
showInfoTable = input.bool(true, "Show Info Table", group="Display Options")
showTradeSignals = input.bool(true, "Show Trade Signals", group="Display Options")
// Table Settings
tablePosition = input.string("Top Right", "Table Position", options=["Top Left", "Top Right", "Bottom Left", "Bottom Right"], group="Table Settings")
tableSize = input.string("Normal", "Table Size", options=["Small", "Normal", "Large"], group="Table Settings")
tableTransparency = input.int(10, "Table Transparency", minval=0, maxval=50, group="Table Settings")
// Professional Dark Theme Color Scheme
colorHalving = input.color(color.new(#ff6b35, 0), "Halving Line Color", group="Colors")
colorProfitStart = input.color(color.new(#4ecdc4, 0), "Profit Start Color", group="Colors")
colorProfitEnd = input.color(color.new(#ff6b6b, 0), "Profit End Color", group="Colors")
colorDCA = input.color(color.new(#ffd93d, 0), "DCA Color", group="Colors")
colorBackground = input.color(color.new(#4ecdc4, 92), "Background Color", group="Colors")
// Timing Settings
profitStartWeeks = input.int(40, "Profit Start (Weeks)", minval=1, group="Timing")
profitEndWeeks = input.int(80, "Profit End (Weeks)", minval=1, group="Timing")
dcaStartWeeks = input.int(135, "DCA Start (Weeks)", minval=1, group="Timing")
// ════════════════════════════════════════════════════════════════════════════════════════════════
// HELPER FUNCTIONS
// ════════════════════════════════════════════════════════════════════════════════════════════════
// Get table position
getTablePosition() =>
switch tablePosition
"Top Left" => position.top_left
"Top Right" => position.top_right
"Bottom Left" => position.bottom_left
"Bottom Right" => position.bottom_right
=> position.top_right
// Get table text size
getTableTextSize() =>
switch tableSize
"Small" => size.tiny
"Normal" => size.small
"Large" => size.normal
=> size.small
// Get table header text size
getTableHeaderSize() =>
switch tableSize
"Small" => size.small
"Normal" => size.normal
"Large" => size.large
=> size.normal
// Calculate weeks from halving date
weeksFromHalving(halvingTimestamp) =>
(time - halvingTimestamp) / (7 * 24 * 60 * 60 * 1000)
// Check if current time is within profit zone
inProfitZone(halvingTimestamp) =>
weeks = weeksFromHalving(halvingTimestamp)
weeks >= profitStartWeeks and weeks <= profitEndWeeks
// Check if current time is within DCA zone
inDCAZone(halvingTimestamp) =>
weeks = weeksFromHalving(halvingTimestamp)
weeks >= dcaStartWeeks
// ════════════════════════════════════════════════════════════════════════════════════════════════
// HALVING DATES & DATA
// ════════════════════════════════════════════════════════════════════════════════════════════════
// Historical halving dates
halving1 = timestamp(2012, 11, 28)
halving2 = timestamp(2016, 7, 9)
halving3 = timestamp(2020, 5, 11)
halving4 = timestamp(2024, 4, 19)
// Store halving data
type HalvingData
float timestamp
string label
string emoji
color lineColor
halvings = array.new<HalvingData>()
array.push(halvings, HalvingData.new(halving1, "1st Halving\n2012", "⛏️", colorHalving))
array.push(halvings, HalvingData.new(halving2, "2nd Halving\n2016", "⛏️⛏️", colorHalving))
array.push(halvings, HalvingData.new(halving3, "3rd Halving\n2020", "⛏️⛏️⛏️", colorHalving))
array.push(halvings, HalvingData.new(halving4, "4th Halving\n2024", "⛏️⛏️⛏️⛏️", colorHalving))
// Get current cycle status
getCurrentCycleStatus() =>
var string result = "⏳ Pre-Halving Phase"
for i = array.size(halvings) - 1 to 0 by 1
halvingData = array.get(halvings, i)
if time >= halvingData.timestamp
weeks = weeksFromHalving(halvingData.timestamp)
if weeks <= profitStartWeeks
result := "🔶 Accumulation Phase"
break
else if weeks <= profitEndWeeks
result := "🟢 Profit Taking Phase"
break
else if weeks <= dcaStartWeeks
result := "⚠️ Bear Market Phase"
break
else
result := "🟡 DCA Phase"
break
result
// Get weeks until next phase
getWeeksUntilNextPhase() =>
var float result = na
for i = array.size(halvings) - 1 to 0 by 1
halvingData = array.get(halvings, i)
if time >= halvingData.timestamp
weeks = weeksFromHalving(halvingData.timestamp)
if weeks <= profitStartWeeks
result := profitStartWeeks - weeks
break
else if weeks <= profitEndWeeks
result := profitEndWeeks - weeks
break
else if weeks <= dcaStartWeeks
result := dcaStartWeeks - weeks
break
else
result := na
break
result
// Get next phase date
getNextPhaseDate() =>
var float result = na
for i = array.size(halvings) - 1 to 0 by 1
halvingData = array.get(halvings, i)
if time >= halvingData.timestamp
weeks = weeksFromHalving(halvingData.timestamp)
if weeks <= profitStartWeeks
result := halvingData.timestamp + (profitStartWeeks * 7 * 24 * 60 * 60 * 1000)
break
else if weeks <= profitEndWeeks
result := halvingData.timestamp + (profitEndWeeks * 7 * 24 * 60 * 60 * 1000)
break
else if weeks <= dcaStartWeeks
result := halvingData.timestamp + (dcaStartWeeks * 7 * 24 * 60 * 60 * 1000)
break
else
result := na
break
result
// Get current phase name
getCurrentPhaseName() =>
var string result = "Pre-Halving"
for i = array.size(halvings) - 1 to 0 by 1
halvingData = array.get(halvings, i)
if time >= halvingData.timestamp
weeks = weeksFromHalving(halvingData.timestamp)
if weeks <= profitStartWeeks
result := "Accumulation"
break
else if weeks <= profitEndWeeks
result := "Profit Taking"
break
else if weeks <= dcaStartWeeks
result := "Bear Market"
break
else
result := "DCA"
break
result
// Get next phase name
getNextPhaseName() =>
var string result = "Accumulation"
for i = array.size(halvings) - 1 to 0 by 1
halvingData = array.get(halvings, i)
if time >= halvingData.timestamp
weeks = weeksFromHalving(halvingData.timestamp)
if weeks <= profitStartWeeks
result := "Profit Taking"
break
else if weeks <= profitEndWeeks
result := "Bear Market"
break
else if weeks <= dcaStartWeeks
result := "DCA"
break
else
result := "Next Halving"
break
result
// Get phase countdown variables
getPhaseCountdown() =>
var float currentHalvingTimestamp = na
var float profitStartWeeksLeft = na
var float profitEndWeeksLeft = na
var float dcaStartWeeksLeft = na
var string profitStartDateText = "N/A"
var string profitEndDateText = "N/A"
var string dcaStartDateText = "N/A"
var string nextPhaseName = "N/A"
var string nextPhaseDateText = "N/A"
for i = array.size(halvings) - 1 to 0 by 1
halvingData = array.get(halvings, i)
if time >= halvingData.timestamp
currentHalvingTimestamp := halvingData.timestamp
weeks = weeksFromHalving(halvingData.timestamp)
// Calculate countdowns
profitStartWeeksLeft := profitStartWeeks - weeks
profitEndWeeksLeft := profitEndWeeks - weeks
dcaStartWeeksLeft := dcaStartWeeks - weeks
// Calculate dates
profitStartDate = halvingData.timestamp + (profitStartWeeks * 7 * 24 * 60 * 60 * 1000)
profitEndDate = halvingData.timestamp + (profitEndWeeks * 7 * 24 * 60 * 60 * 1000)
dcaStartDate = halvingData.timestamp + (dcaStartWeeks * 7 * 24 * 60 * 60 * 1000)
profitStartDateText := str.format("{0,date,yyyy-MM-dd}", profitStartDate)
profitEndDateText := str.format("{0,date,yyyy-MM-dd}", profitEndDate)
dcaStartDateText := str.format("{0,date,yyyy-MM-dd}", dcaStartDate)
// Get next phase
if weeks <= profitStartWeeks
nextPhaseName := "Profit Taking"
nextPhaseDateText := profitStartDateText
break
else if weeks <= profitEndWeeks
nextPhaseName := "Bear Market"
nextPhaseDateText := profitEndDateText
break
else if weeks <= dcaStartWeeks
nextPhaseName := "DCA"
nextPhaseDateText := dcaStartDateText
break
else
nextPhaseName := "Next Halving"
nextPhaseDateText := "N/A"
break
[profitStartWeeksLeft, profitEndWeeksLeft, dcaStartWeeksLeft, profitStartDateText, profitEndDateText, dcaStartDateText, nextPhaseName, nextPhaseDateText]
// ════════════════════════════════════════════════════════════════════════════════════════════════
// BACKTESTING LOGIC
// ════════════════════════════════════════════════════════════════════════════════════════════════
// Variables for tracking signals
var bool longSignal = false
var bool shortSignal = false
var bool buyAtHalving = false
var bool buyAtDCA = false
var bool sellAtProfitEnd = false
var bool shortAtProfitEnd = false
var bool coverAtDCA = false
// Reset signals
longSignal := false
shortSignal := false
buyAtHalving := false
buyAtDCA := false
sellAtProfitEnd := false
shortAtProfitEnd := false
coverAtDCA := false
// Check for buy signals (Halving and DCA zones)
for i = 0 to array.size(halvings) - 1
halvingData = array.get(halvings, i)
weeks = weeksFromHalving(halvingData.timestamp)
// Buy at halving (within 1 week of halving)
if math.abs(weeks) < 1 and weeks >= 0
buyAtHalving := true
longSignal := true
// Buy at DCA start
if math.abs(weeks - dcaStartWeeks) < 0.5
buyAtDCA := true
longSignal := true
// Sell at profit end
if math.abs(weeks - profitEndWeeks) < 0.5
sellAtProfitEnd := true
if enableShortTrades
shortAtProfitEnd := true
shortSignal := true
// Cover short at DCA (same time as long entry)
if math.abs(weeks - dcaStartWeeks) < 0.5 and enableShortTrades
coverAtDCA := true
// Execute trades
if enableBacktesting
// Long entries
if longSignal and (buyAtHalving or buyAtDCA)
strategy.close("SHORT", comment="Cover Short")
strategy.entry("LONG", strategy.long, qty=positionSize/100 * strategy.equity/close, comment=buyAtHalving ? "Buy at Halving" : "Buy at DCA")
// Long exit and short entry
if sellAtProfitEnd and strategy.position_size > 0
strategy.close("LONG", comment="Sell at Profit End")
if enableShortTrades and shortAtProfitEnd
strategy.entry("SHORT", strategy.short, qty=positionSize/100 * strategy.equity/close, comment="Short at Profit End")
// Short cover (already handled above with long entry)
// ════════════════════════════════════════════════════════════════════════════════════════════════
// VISUAL ELEMENTS
// ════════════════════════════════════════════════════════════════════════════════════════════════
// Trade signals visualization
if showTradeSignals
if longSignal and buyAtHalving
label.new(bar_index, low, "🟢 BUY\nHALVING", style=label.style_label_up, color=color.new(color.green, 0), textcolor=color.white, size=size.normal)
if longSignal and buyAtDCA
label.new(bar_index, low, "🟢 BUY\nDCA", style=label.style_label_up, color=color.new(color.green, 0), textcolor=color.white, size=size.normal)
if sellAtProfitEnd
label.new(bar_index, high, "🔴 SELL\nPROFIT END", style=label.style_label_down, color=color.new(color.red, 0), textcolor=color.white, size=size.normal)
if shortAtProfitEnd and enableShortTrades
label.new(bar_index, high, "🔴 SHORT\nPROFIT END", style=label.style_label_down, color=color.new(color.orange, 0), textcolor=color.white, size=size.normal)
// Background gradient for profit zones
var bool showBgGradient = false
if showBackgroundGradient
for i = 0 to array.size(halvings) - 1
halvingData = array.get(halvings, i)
if inProfitZone(halvingData.timestamp)
showBgGradient := true
break
else
showBgGradient := false
bgcolor(showBackgroundGradient and showBgGradient ? colorBackground : na)
// ════════════════════════════════════════════════════════════════════════════════════════════════
// PROFESSIONAL DARK THEME TABLE - ALWAYS VISIBLE
// ════════════════════════════════════════════════════════════════════════════════════════════════
// Get position variables
var string currentPosition = "FLAT"
var color positionColor = color.new(#cccccc, 0)
var string positionEmoji = "⚪"
// Update position variables
currentPosition := strategy.position_size > 0 ? "LONG" : strategy.position_size < 0 ? "SHORT" : "FLAT"
positionColor := strategy.position_size > 0 ? color.new(#00ff88, 0) : strategy.position_size < 0 ? color.new(#ff4444, 0) : color.new(#cccccc, 0)
positionEmoji := strategy.position_size > 0 ? "🟢" : strategy.position_size < 0 ? "🔴" : "⚪"
// Get phase countdown data
[profitStartWeeksLeft, profitEndWeeksLeft, dcaStartWeeksLeft, profitStartDateText, profitEndDateText, dcaStartDateText, nextPhaseName, nextPhaseDateText] = getPhaseCountdown()
// ════════════════════════════════════════════════════════════════════════════════════════════════
// ALERTS
// ════════════════════════════════════════════════════════════════════════════════════════════════
// Enhanced alerts with trade signals
for i = 0 to array.size(halvings) - 1
halvingData = array.get(halvings, i)
weeks = weeksFromHalving(halvingData.timestamp)
if math.abs(weeks) < 0.1 and weeks >= 0
alert("🟢 Bitcoin Halving Cycle: BUY SIGNAL at halving event!", alert.freq_once_per_bar)
if math.abs(weeks - profitEndWeeks) < 0.1
alert("🔴 Bitcoin Halving Cycle: SELL SIGNAL - Last call for profit taking! (" + str.tostring(profitEndWeeks) + " weeks post-halving)", alert.freq_once_per_bar)
if math.abs(weeks - dcaStartWeeks) < 0.1
alert("🟡 Bitcoin Halving Cycle: BUY SIGNAL - DCA accumulation phase has begun! (" + str.tostring(dcaStartWeeks) + " weeks post-halving)", alert.freq_once_per_bar)