yasmanyarciacorcho / trading-stocks Goto Github PK
View Code? Open in Web Editor NEWPlatforms to develop, test, and run stock trading strategies
Platforms to develop, test, and run stock trading strategies
Strategy: vwap v0.0.0.7
Right now we are using a market order to enter a trade and a liquidate to exit from the trade. We are experimenting some numerical differences on our expected exit from the trades.
We would like to test the performance of the swap strategy by sending a limit order to sell just after realizing a market order to buy.
The limit order should be based on the price returned from the market order ticket and our limit order's current risk.
When adding Gap Percentage to line 212 algo is not calculating the gap. Make trades on gap lower than the percentage and is not liquidating, and I think does not liquidate until next gap(need to test this)
The average true range (ATR) is a technical analysis indicator. This indicator will tell us if is a good trade to enter base on Profit exit. Example if the ATR of Symbol (SPY) averegae 1.30 we need to calculate the percentage that had moved and and make a trade if the parameter is between -24% to +24% (-0.31 to +0.31)
The first step in calculating ATR is to find a series of true range values for a security. The price range of an asset for a given trading day is simply its high minus its low. https://www.investopedia.com/terms/a/atr.asp
Current behavior
Currently, we are using the full definition of symbol to store the trading equity information. In many cases around the code, this could be improved to use just the string value of the symbol.
Desired behavior
Use just the symbol string value to try to optimize the code performance and memory requirements.
A possible approach can be to use this tool https://github.com/QuantConnect/Lean
Line 37 AccumulatePositiveTimeRan is not working
Separate per strategy
# All the variables that manages times are written in seconds.
self.ConsolidateSecondsTime = 60 # Define the one min candle.
self.ConsolidateLowPriceTime = 60 # Define low price candle, used on vwap strategy.
self.AccumulatePositiveTimeRan = 0 # Interval time when all equity price should be over the vwap before entering in a buy trade.
First implementation is based on percent
All traders should be closed at the end of the day by forced by liquidating to win or by force.
Note: check if liquidate state is being updated
Parameter to limit how many trades is allow to enter for each symbol.
Note: We need to consider in other version to allow to trade while is winning. Example if a symbol wins allow another trade until have a losing trade.
Strategy:
VWAP strategy
Desired behavior:
Update the Candle lowest price to be the minute candle when the 5 the lowest 5 mins candle is the same as the entry price
Relative Volume (often times called RVOL) or
"Performance by Relative Volatility (TR/ATR)"https://blog.tradervue.com/2015/03/04/new-relative-volatility-report/
What is Relative Volume?
Relative Volume (often times called RVOL) is an indicator that tells traders how current trading volume is compared to past trading volume over a given period.
It is kind of a like a radar for how “in-play” a stock is.
The higher the relative volume is the more in play it is because more traders are watching and trading it.
As traders, this is what we want.
Stocks that have a lot of volume have more liquidity and tend to trade better than stocks with low relative volume.
The RVOL is displayed as a ratio.
So if it is showing 3.5 relative volume, that means it is trading at 3.5 times its normal volume for that time period.
When all this falls in line together we have a recipe for parabolic moves that can make trading months and sometimes even years.
This is also a good metric to watch for potential bottoming or topping in stocks.
As a stock gets oversold or overbought we want to look for volume to get a spike in relative volume which would indicate that buyers and seller are fighting over an important support or resistance level and will likely reverse.
What is an inside day?
You need two bars to define an inside day. The reason for this is obvious when you learn that an inside day is when the low is higher than yesterday’s low and today’s high is lower than yesterday’s high. If both conditions are fulfilled, you have an inside day.
In other words, all price action of an inside day is inside the price action of yesterday. The whole range falls inside the range of yesterday. This chart of the oil futures reveals plenty of inside days (green arrows – ignore the red arrows):
Inside day in trading
Inside day in trading
As you can see, the bars over the green arrows show an inside day and they are quite frequent, but it varies from market to market. It depends on the volatility and the price action between the close and the opening the next day. The above chart is crude oil and this market has many inside days.
Sample from 1/1/21 to 1/31/21. Algo did not trade on 1/6. When try 1/6 alone it trade. Need to test more
Gap works, but if position is open won't closed until another gap
Test conditions:
Given @Carto1984 statements on VWAP v0.0.0.6 when self.accumulatePositiveTimeRan != 0
the algo is not doing any trade.
Sell the equity instead of buying position
TRADE RENMAINS OPEN UNTIL NEXT GAP OF 2%, TO REPLICATE THIS ISSUE TRY
PARAMETER GAP 2 LINE 212
THIS IS THE CODE I USED, I CHANGE
"self.ConsolidateSecondsTime = 60 * 5 # Define the one min candle."
" trading_equity.LastEntryExitOnWinPrice = (trading_equity.LastEntryPrice + (trading_equity.LastEntryPrice - trading_equity.LastEntryExitOnLostPrice)*2)"
CODE ------------
#region imports
from hashlib import new
from AlgorithmImports import *
import enum
#endregion
class LiquidateState(enum.Enum):
Normal = 1 # It is not mandatory to liquidate.
ToWin = 2 # It is mandatory to liquidate if there is a win or there is not a loss. Equity current price >= entry price.
Force = 3 # Liquidate the equity now.
class VWAPStrategy(QCAlgorithm):
def Initialize(self):
#Region - Initialize cash flow
self.SetStartDate(2021, 1, 1) # Set Start Date.
self.SetEndDate(2021, 12, 31) # Set End Date.
self.SetCash(1000000) # Set Strategy Cash.
self.stocksTrading = QCStocksTrading(self)
# Region - Initialize trading equities
## One equity should be traded at least.
equities_symbols = ["aapl", "spy", "tsla", "msft", "ba", "qqq", "fb", "pypl", "twtr", "nvda", "amd", "c", "baba", "bac", "gld", "tgt", "wmt", "amzn", "googl" ]
for symbol in equities_symbols:
equity = self.AddEquity(symbol, Resolution.Second)
self.stocksTrading.AddEquity(equity)
# Region - Set Broker configurations
self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin)
# Region - General configurations
# All the variables that manages times are written in seconds.
self.ConsolidateSecondsTime = 60 * 5 # Define the one min candle.
self.ConsolidateLowPriceTime = 60 * 5 # Define low price candle, used on vwap strategy.
self.AccumulatePositiveTimeRan = 0 # Interval time when all equity price should be over the vwap before entering in a buy trade.
self.IsAllowToTradeByTime = False
self.CurrentTradingDay = -1
self.LiquidateState = LiquidateState.Normal
## Sub region - Schedule events
self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.AfterMarketOpen(equities_symbols[0], 2), self.ResetDataAfterMarketOpenHandler)
self.endTimeToTradeBeforeMarketClose = 300
self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.BeforeMarketClose(equities_symbols[0], self.endTimeToTradeBeforeMarketClose), self.BeforeMarketCloseHandler)
self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.BeforeMarketClose(equities_symbols[0], self.endTimeToTradeBeforeMarketClose + 10), self.BeforeMarketCloseTryToLiquidateOnWinStateHandler)
self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.BeforeMarketClose(equities_symbols[0], self.endTimeToTradeBeforeMarketClose + 5), self.BeforeMarketCloseLiquidateOnDayStateHandler)
# Risk management
self.RiskPerTrade = 200
# Region - Configuration per symbol
for trading_equity in self.stocksTrading.GetTradingEquities():
symbol = trading_equity.Symbol()
# Indicators
# QuantConnect indicators has a field 'name' which returns the indicator name.
self.stocksTrading.RegisterIndicatorForEquity(symbol, 'vwap', self.VWAP(symbol)) # Maybe we can test if it is a good fit for us. Example vwap.Name
self.Consolidate(symbol, timedelta(seconds=self.ConsolidateSecondsTime), self.MinuteConsolidateHandler)
self.Consolidate(symbol, timedelta(seconds=self.ConsolidateLowPriceTime), self.LowConsolidateHandler)
def OnData(self, data):
for trading_equity in self.stocksTrading.GetTradingEquities():
symbol = trading_equity.Symbol()
if not data.Bars.ContainsKey(symbol):
return
equity_current_price = data.Bars[symbol].Price
if self.CurrentTradingDay != self.Time.day:
self.UpdateOpenPriceAfterMarketOpenHandler(trading_equity, equity_current_price)
self.CurrentTradingDay = self.Time.day
if self.ShouldIgnoreOnDataEvent(trading_equity, data):
return
self.UpdateLastBrokenCandle(trading_equity)
# Liquidate by time
if (self.ShouldLiquidateToWin(trading_equity, equity_current_price)
or self.ShouldForceLiquidate()):
self.Liquidate(symbol)
return
if not self.LiquidateState is LiquidateState.Normal:
return
if (not self.Portfolio[symbol].Invested
and self.ShouldEnterToBuy(trading_equity, equity_current_price)):
trading_equity.LastEntryPrice = equity_current_price
trading_equity.LastEntryExitOnLostPrice = trading_equity.LowPriceWindow[0].Low
trading_equity.LastEntryExitOnWinPrice = (trading_equity.LastEntryPrice + (trading_equity.LastEntryPrice - trading_equity.LastEntryExitOnLostPrice)*2)
denominator = trading_equity.LastEntryPrice - trading_equity.LastEntryExitOnLostPrice
if denominator == 0:
return
count_actions_to_buy = int(self.RiskPerTrade / denominator)
self.MarketOrder(symbol, count_actions_to_buy)
trading_equity.SetLastTradeTime(self.Time)
elif self.Portfolio[symbol].Invested:
if (trading_equity.LastEntryExitOnLostPrice > equity_current_price or
trading_equity.LastEntryExitOnWinPrice <= equity_current_price):
self.Liquidate(symbol)
trading_equity.SetLastTradeTime(self.Time)
# Eval when we shouldn't make a trade. This block specify when to trade or not to trade.
def ShouldIgnoreOnDataEvent(self, trading_equity, data):
if not trading_equity.IsAllowToTradeByGapPercent:
return True
if not self.IsAllowToTradeByTime:
return True
vwap = trading_equity.GetIndicator('vwap')
if ((not vwap is None and
not vwap.IsReady) or
not trading_equity.CurrentTradingWindow.IsReady or
not trading_equity.LowPriceWindow.IsReady):
return True
if (self.Time - trading_equity.LastTradeTime).total_seconds() < self.ConsolidateSecondsTime:
return True
return False
def UpdateOpenPriceAfterMarketOpenHandler(self, trading_equity, equity_open_day_price):
if trading_equity.LastDayClosePrice is None:
return
gapPercent = self.CalculateMarketGapPercent(trading_equity.LastDayClosePrice, equity_open_day_price)
trading_equity.IsAllowToTradeByGapPercent = gapPercent > trading_equity.DefaultGapPercentAllowToTrade # add percent per gap. if gapPercent < 2 => means if gap percent is less than 2 percent.
# Region After Market Open
def ResetDataAfterMarketOpenHandler(self):
self.IsAllowToTradeByTime = True
self.LiquidateState = LiquidateState.Normal
for equity in self.stocksTrading.GetTradingEquities():
equity.CurrentTradingWindow = RollingWindow[TradeBar](2)
# EndRegion
# Region - Before market close.
def BeforeMarketCloseHandler(self):
self.IsAllowToTradeByTime = False
for equity in self.stocksTrading.GetTradingEquities():
equity.LastDayClosePrice = self.Securities[equity.Symbol()].Price
def BeforeMarketCloseTryToLiquidateOnWinStateHandler(self):
self.LiquidateState = LiquidateState.ToWin
def BeforeMarketCloseLiquidateOnDayStateHandler(self):
self.LiquidateState = LiquidateState.Force
# EndRegion
# Region Consolidates, update rolling windows
def MinuteConsolidateHandler(self, trade_bar):
equity = self.stocksTrading.GetEquity(trade_bar.Symbol)
self.Log(trade_bar.Symbol)
if not equity is None:
equity.CurrentTradingWindow.Add(trade_bar)
def LowConsolidateHandler(self, trade_bar):
equity = self.stocksTrading.GetEquity(trade_bar.Symbol)
if not equity is None:
equity.LowPriceWindow.Add(trade_bar)
# EndRegion
def ShouldLiquidateToWin(self, trading_equity, equity_current_price):
if (self.LiquidateState is LiquidateState.ToWin
and self.Portfolio[trading_equity.Symbol()].Invested
and trading_equity.LastEntryPrice <= equity_current_price):
return True
return False
def ShouldForceLiquidate(self):
if (self.LiquidateState is LiquidateState.Force
and self.Portfolio.Invested):
return True
return False
# 1 - Enter to buy when the previous candle High price is greater than VWAP current value
# and its Low price is lower than VWAP current value and the same time
# 2 - The equity current price is greater than the previous candle high value.
def ShouldEnterToBuy(self, trading_equity, equity_current_price):
vwap = trading_equity.GetIndicator('vwap')
return (not trading_equity.LastBrokenCandle is None
and self.IsPositiveBrokenCandle(vwap, trading_equity)
and (trading_equity.CurrentTradingWindow[0].Time - trading_equity.LastBrokenCandle.Time).total_seconds() >= self.AccumulatePositiveTimeRan
and equity_current_price > trading_equity.CurrentTradingWindow[0].High)
def IsPositiveBrokenCandle(self, vwap, trading_equity):
candle = trading_equity.CurrentTradingWindow[0]
return (not vwap is None
and (candle.Low < vwap.Current.Value
and candle.Close >= vwap.Current.Value))
def UpdateLastBrokenCandle(self, trading_equity):
current_trading_window = trading_equity.CurrentTradingWindow[0]
vwap = trading_equity.GetIndicator('vwap')
if vwap is None:
return
if (not trading_equity.LastBrokenCandle is None
and current_trading_window.Low < vwap.Current.Value):
trading_equity.LastBrokenCandle = None
if (trading_equity.LastBrokenCandle is None
and self.IsPositiveBrokenCandle(vwap, trading_equity)):
trading_equity.LastBrokenCandle = current_trading_window
def CalculateMarketGapPercent(self, last_close_day_price, current_day_open_price):
return (current_day_open_price - last_close_day_price) / current_day_open_price * 100
class EquityTradeModel:
def init(self, symbol, equity, default_gap_percent_to_trade = 2):
self.__symbol = symbol
self.__equity = equity
self.indicators = {}
self.LastEntryPrice = None
self.LastEntryExitOnLostPrice = None
self.LastEntryExitOnWinPrice = None
self.LastDayClosePrice = None
self.LastTradeTime = None
self.IsAllowToTradeByGapPercent = True
self.DefaultGapPercentAllowToTrade = default_gap_percent_to_trade
self.LastBrokenCandle = None
self.CurrentTradingWindow = None
self.LowPriceWindow = None
def Symbol(self):
return self.__symbol
def Equity(self):
return self.__equity
# Return True if the indicator registered
def RegisterIndicator(self, indicator_name, indicator):
if not indicator_name in self.indicators:
self.indicators[indicator_name] = indicator
return True
return False
# Return True if the indicator unregistered
def UnRegisterIndicator(self, indicator_name):
if indicator_name in self.indicators:
del self.indicators[indicator_name]
return True
return False
def SetLastTradeTime(self, time):
self.LastTradeTime = time
def ResetEquityLastTradeTime(self):
self.SetLastTradeTime(None)
def GetIndicator(self, indicator_name):
if indicator_name in self.indicators:
return self.indicators[indicator_name]
return None
class QCEquityTradeModel(EquityTradeModel):
def init(self, equity):
EquityTradeModel.init(self, equity.Symbol, equity)
self.LastBrokenCandle = None
self.CurrentTradingWindow = RollingWindow[TradeBar](2)
self.LowPriceWindow = RollingWindow[TradeBar](1)
def ResetEquityLastTradeTime(self, qc_algorithm):
self.SetLastTradeTime(qc_algorithm.Time)
class StocksTrading:
def init(self):
self.equities = {}
# return True if the equity was added correctly.
def AddEquity(self, equity_symbol, equity):
if equity_symbol is self.__equitie:
return False
self.equities[equity_symbol] = EquityTradeModel(equity_symbol, equity)
return True
# Return True if the equity was removed correctly.
def RemoveEquity(self, equity_symbol):
del self.equities[equity_symbol]
# Return True if the indicator was registered for the equity
def RegisterIndicatorForEquity(self, equity_symbol, indicator_name, indicator):
if equity_symbol in self.equities:
return self.equities[equity_symbol].RegisterIndicator(indicator_name, indicator)
return False
# Return True if the indicator was unregistered from the equity
def UnRegisterIndicatorForEquity(self, equity_symbol, indicator_name):
if equity_symbol in self.equities:
return self.equities[equity_symbol].UnRegisterIndicator(indicator_name)
return False
# Return the list of symbols that currently are being trading
def GetEquitiesTradingSymbols(self):
return self.equities.keys()
def GetTradingEquities(self):
return self.equities.values()
# Return amount of trading.
def TotalStocksBeingTrading(self):
return len(self.equities)
def IsEquityBeingTrading(self, symbol):
return symbol in self.equities
# Return EquityTradeModel of the parameter 'symbol'
def GetEquity(self, symbol):
if self.IsEquityBeingTrading(symbol):
return self.equities[symbol]
return None
class QCStocksTrading(StocksTrading):
def init(self, qcAlgorithm):
StocksTrading.init(self)
self.__qcAlgorithm = qcAlgorithm
def AddEquity(self, equity):
if not self.GetEquity(equity.Symbol) is None:
return False
equity.SetDataNormalizationMode(DataNormalizationMode.Raw)
qc_equity_model = self.equities[equity.Symbol] = QCEquityTradeModel(equity)
qc_equity_model.LastTradeTime = self.__qcAlgorithm.Time
def RegisterIndicatorForEquity(self, equity_symbol, indicator):
StocksTrading.RegisterIndicatorForEquity(self, equity_symbol, indicator.Name, indicator)
def RegisterIndicatorForEquity(self, equity_symbol, indicator_name, indicator):
StocksTrading.RegisterIndicatorForEquity(self, equity_symbol, indicator_name, indicator)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.