| Overall Statistics |
|
Total Trades 294 Average Win 0.09% Average Loss -0.05% Compounding Annual Return 1.956% Drawdown 4.800% Expectancy 0.506 Net Profit 3.456% Sharpe Ratio 0.44 Loss Rate 48% Win Rate 52% Profit-Loss Ratio 1.87 Alpha -0.018 Beta 2.124 Annual Standard Deviation 0.037 Annual Variance 0.001 Information Ratio 0.005 Tracking Error 0.037 Treynor Ratio 0.008 Total Fees $0.00 |
from datetime import datetime, timedelta
import numpy as np
import pandas as pd
from decimal import Decimal
from System.Drawing import Color
# https://www.investoo.com/pivot-breakout-forex-strategy/
class SvePivotsAlgorithm(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2017, 1, 1)
self.SetEndDate(2018, 10, 1)
self.SetCash(10000)
self.symbol = self.AddForex("EURUSD", Resolution.Minute, Market.Oanda).Symbol
self.pivot = SvePivots(1)
self.SetWarmUp(timedelta(2))
dailyConsolidator = QuoteBarConsolidator(timedelta(1))
dailyConsolidator.DataConsolidated += self.DailyBarHandler
self.SubscriptionManager.AddConsolidator(self.symbol, dailyConsolidator)
self.RegisterIndicator(self.symbol, self.pivot, dailyConsolidator)
fiveMinuteConsolidator = QuoteBarConsolidator(timedelta(minutes=5))
dailyConsolidator.DataConsolidated += self.fiveMinuteBarHandler
self.SubscriptionManager.AddConsolidator(self.symbol, fiveMinuteConsolidator)
self.Schedule.On(self.DateRules.EveryDay(self.symbol), self.TimeRules.AfterMarketOpen(self.symbol, 1), self.EveryDayAfterMarketOpen)
self.bars = RollingWindow[QuoteBar](2)
self.state = None
plot = Chart("PivotPlot")
for i in ["S1","S2","S3","R1","R2","R3"]:
plot.AddSeries(Series(i, SeriesType.Line, 0))
plot.AddSeries(Series("PP", SeriesType.Line, '$', Color.Red))
plot.AddSeries(Series("Price", SeriesType.Line, '$', Color.Blue))
self.AddChart(plot)
def OnData(self, data):
pass
def EveryDayAfterMarketOpen(self):
# establish the market state bias for the day after the market open
# the bias for the day is bullish if the price action opens for the trading day above the central pivot point
if self.Securities[self.symbol].Price > self.pivot.PP:
self.state = True
# the bias for the day is bearish if the price action opens for the trading day below the central pivot point
if self.Securities[self.symbol].Price < self.pivot.PP:
self.state = False
def DailyBarHandler(self, sender, bar):
self.Plot("PivotPlot", 'S1', self.pivot.S1)
self.Plot("PivotPlot", 'S2', self.pivot.S2)
self.Plot("PivotPlot", 'S3', self.pivot.S3)
self.Plot("PivotPlot", 'R1', self.pivot.R1)
self.Plot("PivotPlot", 'R2', self.pivot.R2)
self.Plot("PivotPlot", 'R3', self.pivot.R3)
self.Plot("PivotPlot", 'PP', self.pivot.PP)
self.Plot("PivotPlot", 'Price', self.Securities[self.symbol].Price)
def fiveMinuteBarHandler(self, sender, bar):
''' When the price action eventually breaks out of one boundary,
use the principles of the breakout trade to make the entry and use the next pivot point
in the path of the price action as the profit target, while setting a stop loss below
the broken pivot (long trade) or above the broken pivot (short trade).
'''
if self.IsWarmingUp or not self.pivot.IsReady: return
self.bars.Add(bar)
if not self.bars.IsReady: return
# Be bullish when the price is above the main pivot point
if self.state:
# trip from below to above R1
if self.bars[1].High < self.pivot.R1 < self.bars[0].High:
self.MarketOrder(self.symbol, 1000)
self.LimitOrder(self.symbol, -1000, self.pivot.R2)
self.StopMarketOrder(self.symbol, -1000, self.pivot.R1-Decimal(0.00500))
# trip from below to above R2
if self.bars[1].High < self.pivot.R2 < self.bars[0].High:
self.Transactions.CancelOpenOrders(self.symbol)
self.MarketOrder(self.symbol, 1000)
self.LimitOrder(self.symbol, -1000, self.pivot.R3)
self.StopMarketOrder(self.symbol, -1000, self.pivot.R2-Decimal(0.00500))
# Be bearish when the price is below the main pivot point
if not self.state:
# trip from above to below S1
if self.bars[0].Low < self.pivot.S1 < self.bars[1].Low:
self.MarketOrder(self.symbol, -1000)
self.LimitOrder(self.symbol, 1000, self.pivot.S2)
self.StopMarketOrder(self.symbol, 1000, self.pivot.S1+Decimal(0.00500))
# trip from above to below S2
if self.bars[0].Low < self.pivot.S2 < self.bars[1].Low:
self.Transactions.CancelOpenOrders(self.symbol)
self.MarketOrder(self.symbol, -1000)
self.LimitOrder(self.symbol, 1000, self.pivot.S3)
self.StopMarketOrder(self.symbol, 1000, self.pivot.S2+Decimal(0.00800))
class SvePivots:
def __init__(self, period):
self.Time = datetime.min
self.PP = None
self.R1 = self.R2 = self.R3 = None
self.S1 = self.S2 = self.S3 = None
self.RM1 = self.RM2 = self.RM3 = None
self.SM1 = self.SM2 = self.SM3 = None
self.PH = self.PL = None
self.IsReady = False
def Update(self, input):
self.Time = input.EndTime
self.PP = (input.High + input.Low + input.Close) / Decimal(3) # Pivot point
self.R1 = self.PP*Decimal(2) - input.Low # Resistance 1
self.R2 = self.PP + (input.High - input.Low) # Resistance 2
self.R3 = self.PP*Decimal(2) + (input.High - input.Low*Decimal(2)) # Resistance 3
self.S1 = self.PP*Decimal(2) - input.High # Support 1
self.S2 = self.PP - (input.High - input.Low) # Support 2
self.S3 = self.PP*Decimal(2) - (input.High*Decimal(2) - input.Low) # Support 3
self.RM1 = (self.R1-self.PP)/Decimal(2) + self.PP # Resistance Mean value 1
self.RM2 = (self.R2-self.R1)/Decimal(2) + self.R1 # Resistance Mean value 2
self.RM3 = (self.R3-self.R2)/Decimal(2) + self.R2 # Resistance Mean value 3
self.SM1 = (self.PP-self.S1)/Decimal(2) + self.S1 # Support Mean value 1
self.SM2 = (self.S1-self.S2)/Decimal(2) + self.S2 # Support Mean value 2
self.SM3 = (self.S2-self.S3)/Decimal(2) + self.S3 # Support Mean value 3
self.PH = input.High # Previous day’s high
self.PL = input.Low # Previous day’s low
self.IsReady = self.PP is not None