Has anyone tried an implementation of The Alpha Engine, the forex strategy described in the paper by this name? I am interested in testing it in QC, and I'm surprised that I don't see any previous mention of it in the community.
This strategy ignores the time component and forms bars based on price movement. It seems very similar to using renko charting, and applying a state machine to make trades (using pyramiding) based on reversals and continuations in the bar series. Considering this, should I start from a blank strategy template or pick some existing template? It seems like is a good use case for a consolidator. As I haven't yet finished the bookcamp and the QC LEAN framework still seems a bit daunting, a little guidance would be much appreciated.
Robert Christian
I started coding it up and realized that a consolidator is not a good solution, and instead, it's better / easier to simply store the extremal maximum and extremal minimum, updating with each tick, until the bar is done.
However, it looks like the strategy calls for simultaneous long and short positions (short hedging?), which QC doesn't support, so perhaps options will work for all the short positions.
Shile Wen
Hi Robert,
This seems like an interesting paper that I could look into adding to the Strategy Library,
Best,
Shile Wen
Robert Christian
Hi Shile,
I've been working on implementing the author's charting system they call "Intrinsic Time". Ideally this would be a tool which could employed in any strategy, and that's the objective I'm working towards; reusability. I don't think it's there yet, but here's a starting point. Included are some charts I was able to generate in a research book. Code provided below.
SPY OHLC:
SPY Intrinsic Time (using 3% change delta):
Â
I also have a C# implementation, which employs RollingWindow. I wasn't able to use RollingWindow in Python because it won't accept a Python class as the type parameter (is it possible to use a wildcard type, like the `any` type in TypeScript?).
The other challenges I ran into is that I don't see an obvious way to plot the data in a C# research book, and I don't know to wrap and then import my C# classes in a Python research book, which would allow me to implement this entirely in C#, and then test it in a Python research book, plot the results, and then use the C# code directly in a C# algo.
Research Book
qb = QuantBook() spy = qb.AddEquity("SPY") days = 360 history = qb.History(qb.Securities.Keys, days, Resolution.Daily) import pandas as pd import mplfinance as mpf from IntrinsicTime import IntrinsicTimeChart it = IntrinsicTimeChart(0.03, days + 1) # write every new bar into table struct at IT run-time new_table = {"Date":[], "Open": [], "High": [], "Low": [], "Close": []} def writeBarToTable(bar): new_table["Date"].append(bar.time) new_table["Low"].append(bar.low) new_table["High"].append(bar.high) if bar.direction == 'u': new_table["Open"].append(bar.low) new_table["Close"].append(bar.high) else: new_table["Open"].append(bar.high) new_table["Close"].append(bar.low) it.OnStep = writeBarToTable # push price history into IT for index, row in history.iterrows(): bar = TradeBar() bar.Open = row['open'] bar.High = row['high'] bar.Low = row['low'] bar.Close = row['close'] it.NewCandlestick(index[1], bar) # plot intrinsic time series df = pd.DataFrame(new_table) df.index = df["Date"] mpf.plot(df, type='candlestick') # plot historical price as OHLC spy = history.loc['SPY'] spy.rename(columns={"open": "Open", "high": "High", "low": "Low", "close": "Close", "volume": "Volume"}, inplace=True) mpf.plot(spy)
Â
Intrinsic Time Python Implementation
Note: With full tick data, use the NewPrice method (this is the ideal approach). For OHLC data (which is suboptimal due to loss of resolution), use NewCandlestick. However, note that this method makes a compromise in assuming a particular order for processing the OHLC values per bar, and this may effect your results. If you use 1 second bars, and your percentage change is large enough, I think you won't be impacted by this compromise.
Note: This implementation uses recursion to produce charts without gaps, this is what I understood from the paper as being the intended approach. IOW: Any gaps in real price movement will be filled with bars in the intrinsic time series.
from QuantConnect.Data.Market import TradeBar class IntrinsicTimeBar: reversal: False direction: None time: None high: None low: None def __init__(self, time, high: float, low: float, direction=None, reversal=False): self.reversal = reversal self.direction = direction self.time = time self.high = high self.low = low class IntrinsicTimeChart: maxPercentageChange = None maxLength = None lengthNow = 0 OnStep = None upper = None lower = None def __init__(self, max_percentage_change: float, length = 2): self.maxPercentageChange = max_percentage_change self.maxLength = max(2, length) self.window = [] self.upper = None self.lower = None def __AddBar(self, new_price: float, new_bar: IntrinsicTimeBar): self.window.insert(0, new_bar) length = len(self.window) if length > self.maxLength: self.window.pop(self.maxLength) else: self.lengthNow = length self.upper = new_price self.lower = new_price if self.OnStep: self.OnStep(new_bar) def NewCandlestick(self, time, bar: TradeBar): if self.upper == None: self.upper = bar.Open self.lower = bar.Open avg_level = (self.upper + self.lower) * 0.5 ohlc_order = [ ('Open', abs(avg_level - bar.Open)), ('High', abs(avg_level - bar.High)), ('Low', abs(avg_level - bar.Close)), ('Close', abs(avg_level - bar.Close)) ] ohlc_order = [t[0] for t in sorted(ohlc_order, key=lambda t: t[1])] for prop in ohlc_order: self.NewPrice(time, getattr(bar, prop)) def NewPrice(self, time, price: float): self.upper = price if self.upper == None else max(price, self.upper) self.lower = price if self.lower == None else min(price, self.lower) allowable_change = (self.upper + self.lower) * 0.5 * self.maxPercentageChange if self.upper - self.lower < allowable_change: return new_level = None new_bar = IntrinsicTimeBar(time, self.upper, self.lower, direction=None, reversal=False) possible_high = self.lower + allowable_change possible_low = self.upper - allowable_change if price > possible_high: new_bar.high = new_level = possible_high new_bar.direction = 'u' if self.lengthNow > 0 and self.window[0].direction == 'd': new_bar.reversal = True elif price < possible_low: new_bar.low = new_level = possible_low new_bar.direction = 'd' if self.lengthNow > 0 and self.window[0].direction == 'u': new_bar.reversal = True else: raise Exception('the impossible has happened') self.__AddBar(new_level, new_bar) self.NewPrice(time, price)
Â
Just briefly, some assorted thoughts on programming languages on the platform:
I'm completely new to C#, and I'm really not a fan of OOP languages in general. However, the strong type checking in C# makes it much nicer to work with than Python. Sure would be nice if F# would become usable. I'm not really sure why it's an option on the platform, since selecting F# triggers an error saying "invalid language selection". I asked support and they replied that it's marked as beta, but I don't see beta mentioned anywhere in the interface.
Â
Robert Christian
Feedback, critiques, and suggestions are much appreciated. And especially, any help on how to run my C# code in a python notebook, or how to plot charts in a C# notebook.
Robert Christian
Actually, I spotted a bug in the NewCandlestick method, so I fix that, and posted the updated file as a gist here (which is what I should have done in my earlier reply). Enjoy.
Â
Shile Wen
Hi Robert,
You can use a Python deque to store types not supported by RollingWindows. In addition, we have a GH Issue here for C# plotting, and feel free to subscribe to it to be notified when it's merged.
Best,
Shile Wen
Robert Christian
Here's a C# implementation of intrinsic time.
Robert Christian
The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.
To unlock posting to the community forums please complete at least 30% of Boot Camp.
You can continue your Boot Camp training progress from the terminal. We hope to see you in the community soon!