Overall Statistics
Total Trades
0
Average Win
0%
Average Loss
0%
Compounding Annual Return
0%
Drawdown
0%
Expectancy
0
Net Profit
0%
Sharpe Ratio
0
Loss Rate
0%
Win Rate
0%
Profit-Loss Ratio
0
Alpha
0
Beta
0
Annual Standard Deviation
0
Annual Variance
0
Information Ratio
0
Tracking Error
0
Treynor Ratio
0
Total Fees
$0.00
class TradingSetup(object):
    def __init__(self, symbol, entry, stop, profit, shares, order):
        self.Symbol = symbol
        self.Entry = entry
        self.Stop = stop
        self.Profit = profit
        self.Shares = shares
        self.StopEntryOrder = order
        self.StopLossOrder = None
        self.TakeProfitOrder = None
        self.Active = True
        self.Filled = False


######## NOT CURRENTLY IN USE ##########
class RollingWindowNum(object):
    def __init__(self, symbol, size):
        self.Symbol = symbol
        self.Data = RollingWindow[float](size) #Is there a way to use Decimal instead of float? There would be an error if replace it by Decimal.
        self.Error = True #No data in the beginning = no trades

class SymbolData(object):
    def __init__(self, symbol, barPeriod, windowSize):
        self.Symbol = symbol
        self.BarPeriod = barPeriod
        # A rolling window of data, data needs to be pumped into Bars by using Bars.Update( tradeBar ) and can be accessed like:
        # mySymbolData.Bars[0] - most first recent piece of data
        # mySymbolData.Bars[5] - the sixth most recent piece of data (zero based indexing)
        self.Bars = RollingWindow[IBaseDataBar](windowSize)
  
    # Returns true if all the data in this instance is ready (indicators, rolling windows, ect...)
    def IsReady(self):
        return self.Bars.IsReady and self.SMA.IsReady

    # Returns true if the most recent trade bar time matches the current time minus the bar's period, this
    # indicates that update was just called on this instance
    def WasJustUpdated(self, current):
        return self.Bars.Count > 0 and self.Bars[0].Time == current - self.BarPeriod
# QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
# Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from clr import AddReference
AddReference("System")
AddReference("QuantConnect.Algorithm")
AddReference("QuantConnect.Common")

from System import *
from QuantConnect import *
from QuantConnect.Orders import *
from QuantConnect.Algorithm import *
from QuantConnect.Data.Consolidators import *
from QuantConnect.Data.Market import *
from QuantConnect.Indicators import *
from datetime import datetime, timedelta
import pandas as pd
import numpy as np
from classes import *
from decimal import Decimal   # Important: import decimal.Decimal class


class DayTrading(QCAlgorithm):
    def Initialize(self):
        self.SetStartDate(2016,1,4) #Set Start Date
        self.SetEndDate(2016,1,7)  #Set End Date
        self.SetCash(100000)    #Set Strategy Cash
        self.R = 200

        #self.UniverseSettings.Resolution = Resolution.Minute
        self.UniverseSettings.ExtendedMarketHours = True
        self.AddUniverse("gapfinder", Resolution.Hour, self.Filter)
        #self.AddUniverse(self.Filter)
        self.AddEquity("SPY")
        
        self.gappers = []
        self.universe = []
        self.LookingForBreakout = False #When true, the bot starts to look for high wave candle
        self.PrevDay = self.Time - timedelta(1)

        #self.PrevDayClose[sym] = RollingWindowNum(symbol, 5)
            
        #threeMinConsolidator = TradeBarConsolidator(timedelta(minutes=3))
            # attach our event handler. The event handler is a function that will
            # be called each time we produce a new consolidated piece of data.
        #threeMinConsolidator.DataConsolidated += self.threeMinBarHandler
            # this call adds our 3-minute consolidator to
            # the manager to receive updates from the engine
        #self.SubscriptionManager.AddConsolidator(sym, threeMinConsolidator)
        
        self.Schedule.On(self.DateRules.EveryDay("SPY"), \
            self.TimeRules.AfterMarketOpen("SPY", 120), \
            Action(self.MarketCloseLiquidate))

    
    def Filter(self, coarse):
        #if self.Time.hour != 0 and self.Time.hour != 16: # I'm looking at 9:00
        #    return self.universe
        self.Log("test")
        self.Log("c:"+str(coarse))
        
        try:
            sortedByDollarVolume = sorted(coarse, key=lambda x: x.DollarVolume, reverse=True)
        except:
            return self.universe
        filtered = [ x.Symbol for x in sortedByDollarVolume 
                    if x.Price > 5 and x.DollarVolume > 10000000 ]
        gappers = []
        self.Log(filtered)
        for sym in filtered:
            if self.PrevDay != None :
                bar = self.History(sym, self.PrevDay, self.PrevDay, Resolution.Daily)
                if not bar.empty :
                    GapPercentage = (sym.Price - bar.close) / bar.close
                    self.Log(GapPercentage)
                    
        self.universe = gappers
        return gappers
    
    def threeMinBarHandler(self, sender, bar):
        #This is our event handler for our 3-minute trade bar defined above in Initialize(). 
        #So each time the consolidator produces a new 3-minute bar, this function will be called automatically. 
        #The sender parameter will be the instance of the IDataConsolidator that invoked the event
        
        if bar.Symbol.Value not in self.gappers: #Only trade gappers.
            return
        if self.LookingForBreakout == True :
            #self.Log("bar:" + str(bar.Symbol.Value))
            #self.Log(self.gappers)
            if self.IsHighWave(bar) :
                self.Log("Highwave found! " + str(bar.High) + str(bar.Low) + str(bar.Open) + str(bar.Close))
                newTicket = self.StopLimitOrder(bar.Symbol, round(self.R / (bar.High - bar.Low) ) , bar.High , bar.High)
                self.Trades.append( TradingSetup(bar.Symbol, bar.High, bar.Low, 2*bar.High - bar.Low, round(self.R / (bar.High - bar.Low) ), newTicket) )
            return

    def IsHighWave(self, bar):
        HighLowDiff = bar.High - bar.Low
        OpenCloseDiff = bar.Open - bar.Close
        if  HighLowDiff / bar.Open >= 0.005 and ( OpenCloseDiff == 0 or ( HighLowDiff / OpenCloseDiff >= 2 and (bar.High - bar.Open) / OpenCloseDiff >=0.5 and (bar.Close - bar.Low) / OpenCloseDiff >=0.5 )) : 
            return True
        return False
    
    ##### ORDER EVENT:entry triggered/stop triggered/tp triggered ######         
    def OnOrderEvent(self, orderEvent):
        #order = self.Transactions.GetOrderById(orderEvent.OrderId)
        self.Log(orderEvent)
        for trade in self.Trades :
            if orderEvent.OrderId == trade.StopEntryOrder.OrderId :
                if orderEvent.Status == OrderStatus.Canceled :
                    return
                if orderEvent.Status == OrderStatus.PartiallyFilled :
                    return #To trade live, it needs a better behaviour
                if orderEvent.Status == OrderStatus.Filled :
                    trade.StopLossOrder = self.StopMarketOrder(trade.Symbol, -trade.Shares, trade.Stop)
                    trade.TakeProfitOrder = self.LimitOrder(trade.Symbol, -trade.Shares, trade.Profit)
                    self.Log("SL@"+str(trade.Stop)+":" + str(trade.StopLossOrder))
                    self.Log("TP@"+str(trade.Profit)+":" + str(trade.TakeProfitOrder))

                    return
            if trade.StopLossOrder != None and orderEvent.OrderId == trade.StopLossOrder.OrderId and orderEvent.Status == OrderStatus.Filled :
                #if trade.TakeProfitOrder != None:
                trade.TakeProfitOrder.Cancel() #One cancel the other
                return
            if trade.TakeProfitOrder != None and orderEvent.OrderId == trade.TakeProfitOrder.OrderId and orderEvent.Status == OrderStatus.Filled :
                #if trade.StopLossOrder != None:
                trade.StopLossOrder.Cancel() #One cancel the other
                return

            

    def MarketCloseLiquidate(self):
        self.Liquidate()
        self.PrevDay = self.Time
        openOrders = self.Transactions.GetOpenOrders()
        
        if len(openOrders) > 0:
            for x in openOrders:
                self.Transactions.CancelOrder(x.Id)
                #self.Log(str(x.Id) + " canceled")
        

    def OnData(self, data):
        self.data = data