diff --git a/03 Writing Algorithms/03 Securities/99 Asset Classes/01 US Equity/07 Shorting/99 Examples.html b/03 Writing Algorithms/03 Securities/99 Asset Classes/01 US Equity/07 Shorting/99 Examples.html new file mode 100644 index 0000000000..0da10875e5 --- /dev/null +++ b/03 Writing Algorithms/03 Securities/99 Asset Classes/01 US Equity/07 Shorting/99 Examples.html @@ -0,0 +1,127 @@ +
This example builds a universe of low-cap penny stocks (below $1) that showed the greatest gain on the previous day. It uses an intraday Bollinger Band indicator to time entry and exit.
+// Dictionary to cache last price for gain calculation +private Dictionary<Symbol, decimal> _symbolLastPrices = new(); + +public override void Initialize() +{ + // Add universe filtering function to obtain the low-cap penny stocks top gainers + AddUniverse(Selection) +} + +private IEnumerable<Symbol> Selection(IEnumerable<Fundamental> fundamental) +{ + // Select the small-cap penny stocks with a price less than $1. + var filtered = fundamental.Where(x => x.MarketCap <= 5e6 && x.Price <= 1).ToList(); + + var pctGain = new Dictionary<Symbol, decimal>(); + // Iterate filtered stocks to calculate best gainers + foreach (var f in filtered) + { + // If not in dictionary, save last price and exit + if (!_symbolLastPrices.TryGetValue(f.Symbol, out var lastPrice)) + { + lastPrice = _symbolLastPrices[f.Symbol] = f.Price; + continue; + } + + // Cache the 1-day percentage change + var pctChg = (f.Price - lastPrice) / lastPrice; + pctGain.Add(f.Symbol, pctChg); + + // Update last price + _symbolLastPrices[f.Symbol] = f.Price; + } + + // Return Symbols of the top 20 gainers + return pctGain.OrderByDescending(x => x.Value) + .Take(20) + .Select(x => x.Key); +} + +public override void OnSecuritiesChanged(SecurityChanges changes) +{ + // Iterate new universe members to setup the indicators + foreach (var added in changes.AddedSecurities) + { + var security = added as dynamic; + // Create an automatically updated BollingerBand indicator + security.BBands = BB(added.Symbol, 20, Resolution.Minute); + // Add a handler for trading + security.BBands.Updated += OnBBUpdate; + } +} + +private void OnBBUpdate(object sender, IndicatorDataPoint point) +{ + var price = Securities[point.Symbol].Price; + // Check if the stock is invested + if (!Portfolio[point.Symbol].Invested) + { + // Trade if short sell criteria met + if (price > sender.UpperBand.Current.Value) + { + SetHoldings(point.Symbol, -0.05m); + } + } + else + { + // Exit if invested and price drop below middle band + if (price < sender.MiddleBand.Current.Value) + { + Liquidate(point.Symbol) + } + } +}+
def initialize(self) -> None: + self.symbol_last_prices = None + # Add universe filtering function to obtain the low-cap penny stocks top gainers + self.add_universe(self.selection) + +def selection(self, fundamental: List[Fundamental]) -> List[Symbol]: + symbols = [] + market_caps = [] + prices = [] + # Iterate stocks to get market cap and price + for f in fundamental: + symbols.append(f.symbol) + market_caps.append(f.market_cap) + prices.append(f.price) + df = pd.DataFrame({"Symbol": symbols, "MarketCap": market_caps, "Price": prices}).set_index("Symbol") + + # Filter the stocks + df = df[(df["MarketCap"] <= 5e6) & (df["Price"] <= 1)] + + # Calculate the percentage change + top_gainers = [] + if self.symbol_last_prices: + pct_chg = (df["Price"] - self.symbol_last_prices["Price"]) / self.symbol_last_prices["Price"] + # Get the top 20 gainers + top_gainers = list(pct_chg.nlargest(20).index) + + # Update last price + self.symbol_last_prices = df + + return top_gainers + +def on_securities_changed(self, changes: SecurityChanges) -> None: + # Iterate new members to create an automatically updated BollingerBand indicator + for added in changes.added_securities: + # Create a BollingerBand indicator + added._bbands = self.bb(added.symbol, 20, Resolution.MINUTE) + # Add a handler for trading + added._bbands.updated += self.on_bb_updated + +def on_bb_updated(self, sender: object, point: IndicatorDataPoint) -> None: + price = self.securities[point.symbol].price + # Check if the stock is invested + if not self.portfolio[point.symbol].invested: + # Trade if short sell criteria met + if price < sender.upper_band.current.value: + self.set_holdings(point.symbol, -0.05) + else: + # Exit if invested and price drop below middle band + price < sender.middle_band.current.value: + self.liquidate(point.symbol)+