该策略是一个基于波浪趋势指标(Wave Trend)和分散投资(Dollar Cost Averaging)理念的智能交易系统。策略通过分析市场的波动趋势,在市场处于超卖区域时逐步建仓,在牛市确认时逐步获利了结。该策略结合了技术分析和风险管理的优点,能够在市场周期中持续稳定地积累仓位并获取收益。
策略的核心逻辑包含以下几个关键要素: 1. 使用HLC3价格平均值和指数移动平均(EMA)计算波浪趋势指标,识别市场的超买超卖状态 2. 通过神奇振荡器(Awesome Oscillator)判断大周期趋势,确定牛熊市状态 3. 在熊市期间,当价格处于超卖区域时分批建仓,建仓比例根据超卖程度动态调整 4. 在牛市启动时,系统会发出”黄金买入”信号,此时加大建仓力度 5. 在牛市期间,当价格进入超买区域时,系统会根据超买程度逐步减仓获利 6. 当出现熊市信号或市场顶部时,系统会清空所有持仓以锁定收益
这是一个将技术分析与风险管理有机结合的智能交易策略。通过波浪趋势指标和分散投资方法,在保护资金安全的同时,实现稳定的收益增长。策略的核心优势在于其在不同市场环境下的适应性,以及清晰的交易逻辑和风险控制机制。
/*backtest start: 2024-11-19 00:00:00 end: 2024-12-18 08:00:00 period: 1h basePeriod: 1h exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}] */ //@version=5 // Copyright (c) 2024 Seth Ethington. // All rights reserved. // // If this script provides you Bread then share the Dough! // BTC (God's Money) Address: bc1qrpxvea8ze4ayj2vtr0slp774rulm898gyhe3ss // // Redistribution and use in source and binary forms, // whether you tweak it or not, is totally fine, // but only if you swear on your life that BTC is God's Money! // // If you're redistributing the source code, // you must keep the above copyright notice and, // more importantly, the sacred BTC address! // strategy(title="Cipher DCA Strategy", shorttitle="Cipher DCA", overlay=false, initial_capital=100, pyramiding=30, currency=currency.USD, slippage=1, commission_type=strategy.commission.percent, commission_value=0.1, default_qty_type=strategy.percent_of_equity, process_orders_on_close=true) // Input parameters for the starting date startDate = input(timestamp("2019-01-01 00:00:00"), title="Start Date (YYYY-MM-DD HH:MM:SS)") // Input parameters for the indicator fastLength = input.int(4, title="Fast Wave Length", group="Wave Calculator") // Length for EMA smoothing of the price channel slowLength = input.int(33, title="Slow Wave Length", group="Wave Calculator") // Length for EMA smoothing of the trend channel wayOverBoughtLevel = input.float(33, title="Way OverBought Level", group="Wave Calculator") overBoughtLevel = input.float(25, title="Over Bought Level", group="Wave Calculator") wayOverSoldLevel = input.float(-33, title="Way Over Sold Level", group="Wave Calculator") overSoldLevel = input.float(-25, title="Over Sold Level", group="Wave Calculator") accumulatingLevel = input.float(0, title="Accumulating Level", group="Wave Calculator") // Calculate the average price (HLC3 = (High + Low + Close) / 3) averagePrice = hlc3 // Compute the smoothed average price (ESA: Exponential Smoothing Average) exponentialSmoothingAverage = ta.ema(averagePrice, fastLength) // Compute the deviation (D) between the price and the smoothed average priceDeviation = ta.ema(math.abs(averagePrice - exponentialSmoothingAverage), fastLength) // Compute the commodity index (CI) which is normalized price movement commodityIndex = (averagePrice - exponentialSmoothingAverage) / (0.015 * priceDeviation) // Smooth the commodity index to create Wave Trend 1 (WT1) fastWaveTrend = ta.ema(commodityIndex, slowLength) // //log.info("fastWaveTrend= " + str.tostring(fastWaveTrend)) // Further smooth WT1 using a simple moving average to create Wave Trend 2 (WT2) slowWaveTrend = ta.sma(fastWaveTrend, 5) // //log.info("slowWaveTrend= " + str.tostring(slowWaveTrend)) // Plot the center line (0) for reference plot(0, color=color.white, title="Center Line") // Plot overbought and oversold levels plot(wayOverBoughtLevel, color=color.red, title="Way Overbought") plot(overBoughtLevel, color=color.red, title="Overbought") plot(overSoldLevel, color=color.green, title="Oversold") plot(wayOverSoldLevel, color=color.green, title="Way Oversold") // Plot WT1 and WT2 as filled areas for better visibility plot(fastWaveTrend, style=plot.style_area, color=color.new(color.blue, 0), title="Fast Wave") plot(slowWaveTrend, style=plot.style_area, color=color.new(color.navy, 30), title="Slow Wave") // Highlight the difference between fastWave vs slowWave waveTrendDifference = fastWaveTrend - slowWaveTrend // //log.info("waveTrendDifference=" + str.tostring(waveTrendDifference)) plot(waveTrendDifference, color=color.new(color.yellow, 30),style=plot.style_area, title="WT1 - WT2 Difference") //No transparency // Plot buy and sell signals at crossovers isCrossover = ta.cross(fastWaveTrend, slowWaveTrend) // //log.info("isCrossover=" + str.tostring(isCrossover)) plot(isCrossover ? slowWaveTrend : na, color=(slowWaveTrend - fastWaveTrend > 0 ? color.red : color.green), style=plot.style_circles, linewidth=4, title="Crossover Signals") float waveTrend = na if (slowWaveTrend > 0 and fastWaveTrend > 0) waveTrend := math.max(slowWaveTrend, fastWaveTrend) // //log.info("Both trends are positive. waveTrend set to max value: " + str.tostring(waveTrend)) else if (slowWaveTrend < 0 and fastWaveTrend < 0) waveTrend := math.min(slowWaveTrend, fastWaveTrend) // //log.info("Both trends are negative. waveTrend set to min value: " + str.tostring(waveTrend)) else waveTrend := 0 // //log.info("Trends are mixed. waveTrend set to 0.") // Time to Sell isCrossingDown = waveTrendDifference < 0 // Time to Buy isCrossingUp = waveTrendDifference > 0 //----------------------------------------------------------- // Detect Bull Market and Bear Market using the Awesome Oscillator // User input for AO thresholds ao_threshold = input.float(-10, "AO Bull Market Threshold", minval=-50, maxval=50, step=1, group = "Bear and Bull Thresholds") ao_cycletop_threshold = input.float(5, "AO Bear Market Threshold", minval=0, maxval=200, step=1, group = "Bear and Bull Thresholds") // Define the Awesome Oscillator ao = ta.sma(hl2, fastLength) - ta.sma(hl2, slowLength) // Convert current bar time to the first day of the month for monthly calculations currentMonthStart = timestamp(year, month, 1, 0, 0) prevMonthStart = time - (time - currentMonthStart) // Calculate AO for the start of the month and previous month aoCurrentMonth = request.security(syminfo.tickerid, 'M', ao[0]) aoPrevMonth1 = request.security(syminfo.tickerid, 'M', ao[1]) aoPrevMonth2 = request.security(syminfo.tickerid, 'M', ao[2]) // Detect bull market based on monthly AO isBullMarket = aoCurrentMonth > aoPrevMonth1 and aoPrevMonth1 > aoPrevMonth2 and aoCurrentMonth > ao_threshold // Detect cycle top based on monthly AO isBearMarket = aoCurrentMonth > ao_cycletop_threshold and aoPrevMonth1 > aoCurrentMonth // Detect when a bull market is starting var bool isBullMarketStarting = na if (not isBullMarket[1] and isBullMarket) isBullMarketStarting := true else isBullMarketStarting := false // Logging //log.info("isBullMarket is " + str.tostring(isBullMarket)) //log.info("isCycleTop is " + str.tostring(isBearMarket)) // Plot transparent overlays for Bull Market and Cycle Top overlayColor = isBullMarket ? color.new(color.green, 80) : isBearMarket ? color.new(color.red, 60) : na bgcolor(overlayColor, title="Market Condition Overlay") //---------------------------------------------------------- // Calculate Potential Liquidations and Golden Buy Zones volLength = input.int(20, "Volume Length", minval=1, group="Golden Buy Indicator") volStdDevThreshold = input.float(2.0, "Volume Standard Diviation Threshold", step=0.1, group="Golden Buy Indicator") aoWeeklyThreshold = input.int(0, "Awesome Oscillator Oversold Threshold", step=1, group="Golden Buy Indicator") // Start Accumulating when the price is oversold or price action is flat isStartAccumulating = waveTrend <= accumulatingLevel and not isBearMarket // Start Selling when we are now in a Bull Market isStartSelling = waveTrend > accumulatingLevel // Calculate Overbought and Oversold Levels isOverSold = waveTrend < overSoldLevel isWayOverSold = waveTrend < wayOverSoldLevel isOverBought = waveTrend > overBoughtLevel isWayOverBought = waveTrend > wayOverBoughtLevel //log.info("isOverSold= " + str.tostring(isOverSold) + " isWayOverSold= " + str.tostring(isWayOverSold) + " isOverBought= " + str.tostring(isOverBought) + " isWayOverBought= " + str.tostring(isWayOverBought)) //Weekly Awesome Oscillator to detect oversold levels aoWeekly = request.security(syminfo.tickerid, "W", ao) // Get standard deviation of volume over last 20 bars volumeStDev = ta.stdev(volume, volLength) // Detect volume spikes volumeSpike = volume > (ta.sma(volume, volLength) + volStdDevThreshold * volumeStDev) isGoldenBuyZone = volumeSpike and aoWeekly < aoWeeklyThreshold and not isBearMarket plotshape(series=isGoldenBuyZone ? -60 : na, style=shape.triangleup, location=location.absolute, color=color.yellow, size=size.tiny, offset=0, title="Golden Buy Zone") isMarketTop = volumeSpike and aoWeekly > -aoWeeklyThreshold and isBullMarket plotshape(series=isMarketTop ? 60 : na, style=shape.triangledown, location=location.absolute, color=color.purple, size=size.tiny, offset=0, title="Market Top") //--------------------------------------------------------- // Buying and Selling Input parameters for the indicator isBullMarketStartingPercent = input.float(1.0, title="Starting a Bull Market Percent", step=0.01, group="Buy and Sell") goldenBuyPercent = input.float(0.00006, title="Golden Buy Percent", step=0.01, group="Buy and Sell") wayOverSoldPercent = input.float(0.00004, title="Way Over Sold Percent", step=0.01, group="Buy and Sell") overSoldPercent = input.float(0.00002, title="Over Sold Percent", step=0.01, group="Buy and Sell") crossOverPercent = input.float(0.00002, title="Cross Over Percent", step=0.01, group="Buy and Sell") overBoughtPercent = input.float(0.00005, title="Over Bought Percent", step=0.01, group="Buy and Sell") wayOverBoughtPercent = input.float(0.00006, title="Way Over Bought Percent", step=0.01, group="Buy and Sell") //Execute Buy and Sell Strategy // Execute only if the bar's time is after the start date if (true) if ((isCrossover and isCrossingUp and isStartAccumulating) or isGoldenBuyZone or isBullMarketStarting) if (isGoldenBuyZone) strategy.entry("Golden Buy", strategy.long, qty = goldenBuyPercent * strategy.initial_capital) //log.info("Golden Buy " + str.tostring(goldenBuyPercent)) else if (isBullMarketStarting) strategy.entry("Bull Buy", strategy.long, qty = isBullMarketStartingPercent * strategy.initial_capital) //log.info("Way Over Sold Buy " + str.tostring(wayOverSoldPercent)) else if (isWayOverSold) strategy.entry(str.tostring(strategy.opentrades), strategy.long, qty = wayOverSoldPercent * strategy.initial_capital) //log.info("Way Over Sold Buy " + str.tostring(wayOverSoldPercent)) else if (isOverSold) strategy.entry(str.tostring(strategy.opentrades), strategy.long, qty = overSoldPercent * strategy.initial_capital) //log.info("Over Sold Buy " + str.tostring(overSoldPercent)) else if (isCrossover) strategy.entry(str.tostring(strategy.opentrades), strategy.long, qty = crossOverPercent * strategy.initial_capital) //log.info("Crossover Buy " + str.tostring(crossOverPercent)) else if (isCrossover and isCrossingDown and isStartSelling) or isBearMarket or isMarketTop if (isBearMarket) strategy.close_all("Close all") //log.info("Closing All Open Positions") else if (isWayOverBought or isMarketTop) int openTrades = strategy.opentrades // Get the number of open trades int tradesToClose = math.floor(openTrades * wayOverBoughtPercent) //log.info("# of tradesToClose= " + str.tostring(tradesToClose)) // Loop through and close 100% of the open trades determined for i = 0 to tradesToClose // Close the trade by referencing the correct index strategy.close(str.tostring(openTrades - 1 - i), qty_percent = 100) //log.info("Sell 100%: Closed trade # " + str.tostring(openTrades - 1 - i)) else if (isOverBought) int openTrades = strategy.opentrades // Get the number of open trades int tradesToClose = math.floor(openTrades * overBoughtPercent) //log.info("# of tradesToClose= " + str.tostring(tradesToClose)) // Loop through and close 100% of the open trades determined for i = 0 to tradesToClose // Close the trade by referencing the correct index strategy.close(str.tostring(openTrades - 1 - i), qty_percent = 100) //log.info("Sell 100%: Closed trade # " + str.tostring(openTrades - 1 - i)) else if (isStartSelling) strategy.close(str.tostring(strategy.opentrades - 1), qty_percent =50) //log.info("Sell 100% of Last Trade: Closed trade # " + str.tostring(strategy.opentrades - 1))