Moon Phase Strategy
//@version=5strategy("Moon Phases", overlay=true)
waxingMoonColorInput = input.color(color.blue, "Waxing Moon")waningMoonColorInput = input.color(color.white, "Waning Moon")
var bool longCondition = falsevar bool shortCondition = falsevar int moonPhaseAdjustedGlobal = na
if timeframe.ismonthly runtime.error("Unsupported timeframe.")
dayofyear(_time) => _year = year(_time) leapYear = (_year % 400 == 0) or (_year % 4 == 0 and _year % 100 != 0) dayCount = array.from(31, leapYear ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31) timeMonth = month(_time) dayofyear = 0 if timeMonth > 1 for i = 0 to timeMonth - 2 dayofyear += dayCount.get(i) dayofyear + dayofmonth(_time)
getUNIXTimeFromJD(julianDay) => z = math.floor(julianDay + 0.5) f = (julianDay + 0.5) % 1 alpha = math.floor((z - 1867216.25) / 36524.25) a = (z < 2299161) ? z : (z + 1 + alpha - math.floor(alpha / 4.0)) b = a + 1524 c = math.floor((b - 122.1) / 365.25) d = math.floor(365.25 * c) e = math.floor((b - d) / 30.6001) dayFloat = b - d - math.floor(30.6001 * e) + f _day = int(dayFloat) _month = (e < 13.5) ? int(e - 1) : int(e - 13) _year = (_month > 2.5) ? int(c - 4716) : int(c - 4715) secondTotal = int((dayFloat % 1) * 60 * 60 * 24) _hour = secondTotal / (60 * 60) _minute = (secondTotal - (_hour * 60 * 60)) / 60 _second = secondTotal % 60 timestamp(_year, _month, _day, _hour, _minute, _second)
getLastNewMoon(_time) => _year = year(_time) dayOfYear = dayofyear(_time) k = (dayOfYear / 364.25 + _year - 1900) * 12.3685 int moonPhase = na int moonPhaseAdjustedLocal = na // Declare the local moonPhaseAdjusted variable
// 0 is equal to the fractional part of the new moon // 0.25 - first quarter, 0.5 - full moon, 0.75 - third quarter if ((k % 1.0) < 0.5) k := math.floor(k) moonPhase := +1 // Swap the moonPhase values to represent Full Moon as +1 and New Moon as -1 else k := math.floor(k) + 0.5 moonPhase := -1
t = k / 1236.85 // mean anomaly of the sun at the time julianDate anomalySun = math.toradians(359.2242 + (29.10535608 * k) - (0.0000333 * math.pow(t, 2)) - (0.00000347 * math.pow(t, 3))) // mean anomaly of the moon at the time julianDate anomalyMoon = math.toradians(306.0253 + (385.81691806 * k) + (0.0107306 * math.pow(t, 2)) + (0.00001236 * math.pow(t, 3))) // argument of latitude of the moon f = math.toradians(21.2964 + ((390.67050646 * k) - (0.0016528 * math.pow(t, 2)) - (0.00000239 * math.pow(t, 3)))) dev = (0.1734 - (0.000393 * t)) * math.sin(anomalySun) + 0.0021 * math.sin(2 * anomalySun) - 0.4068 * math.sin(anomalyMoon) + 0.0161 * math.sin(2 * anomalyMoon) - 0.0004 * math.sin(3 * anomalyMoon) + 0.0104 * math.sin(2 * f) - 0.0051 * math.sin(anomalySun + anomalyMoon) - 0.0074 * math.sin(anomalySun - anomalyMoon) + 0.0004 * math.sin(2 * f + anomalySun) - 0.0004 * math.sin(2 * f - anomalySun) - 0.0006 * math.sin(2 * f + anomalyMoon) + 0.0010 * math.sin(2 * f - anomalyMoon) + 0.0005 * math.sin(anomalySun + 2 * anomalyMoon)
julianDate = 2415020.75933 + (29.53058868 * k) + (0.0001178 * math.pow(t, 2)) - (0.000000155 * math.pow(t, 3)) + (0.00033 * math.sin(math.toradians(166.56) + (math.toradians(132.87) * t) - (math.toradians(0.009173) * math.pow(t, 2)))) + dev timeLastMoonPhase = getUNIXTimeFromJD(julianDate) timeLastMoonPhase := timeLastMoonPhase >= _time ? timeLastMoonPhase[1] : timeLastMoonPhase
moonPhaseAdjustedLocal := barstate.isfirst or ta.change(timeLastMoonPhase) ? moonPhase : moonPhaseAdjustedLocal[1] moonType = ta.change(moonPhaseAdjustedLocal) ? moonPhase : na [moonPhaseAdjustedLocal, moonType]
[_, moonType] = getLastNewMoon(time_close)
// Entry conditionsif moonType == -1 // Enter long when there is a Full Moon (moonType = -1) longCondition := true shortCondition := falseif moonType == 1 // Enter short when there is a New Moon (moonType = +1) longCondition := false shortCondition := true
// Exit conditionsif longCondition and moonType == 1 // Close long position when there is a New Moon (moonType = +1) longCondition := falseif shortCondition and moonType == -1 // Close short position when there is a Full Moon (moonType = -1) shortCondition := false
if longCondition strategy.entry("Long", strategy.long)
if shortCondition strategy.entry("Short", strategy.short)
if not longCondition and strategy.position_size > 0 strategy.close("Long")
if not shortCondition and strategy.position_size < 0 strategy.close("Short")
plotshape(moonType == 1, "New Moon", shape.circle, location.abovebar, color.new(waxingMoonColorInput, 50), size=size.normal, display=display.pane)plotshape(moonType == -1, "Full Moon", shape.circle, location.belowbar, color.new(waningMoonColorInput, 50), size=size.normal, display=display.pane)bgcolor(color.new(moonPhaseAdjustedGlobal == 1 ? waxingMoonColorInput : waningMoonColorInput, 95))