Overall Statistics |
Total Trades 799 Average Win 3.76% Average Loss -2.22% Compounding Annual Return 50.927% Drawdown 56.100% Expectancy 0.250 Net Profit 406.052% Sharpe Ratio 0.78 Loss Rate 54% Win Rate 46% Profit-Loss Ratio 1.69 Alpha -0.332 Beta 56.437 Annual Standard Deviation 0.576 Annual Variance 0.332 Information Ratio 0.756 Tracking Error 0.576 Treynor Ratio 0.008 Total Fees $146691.44 |
from clr import AddReference AddReference("System") AddReference("QuantConnect.Common") AddReference("QuantConnect.Algorithm") AddReference("QuantConnect.Algorithm.Framework") from System import * from QuantConnect import * from QuantConnect.Data.Consolidators import * from QuantConnect.Data.Market import * from QuantConnect.Indicators import * from QuantConnect.Orders import * from QuantConnect.Brokerages import * from QuantConnect.Algorithm import * from QuantConnect.Algorithm.Framework import * from QuantConnect.Algorithm.Framework.Alphas import * from QuantConnect.Algorithm.Framework.Execution import * from QuantConnect.Algorithm.Framework.Portfolio import * from QuantConnect.Algorithm.Framework.Risk import * from QuantConnect.Algorithm.Framework.Selection import * class MovingAverageCrossAlpha(AlphaModel): def __init__(self, fast_ma_len, slow_ma_len, prices=None, resolution=Resolution.Daily, algorithm=None): self.Name = "MovingAverage" self.ma_fast_len = fast_ma_len self.ma_slow_len = slow_ma_len self.resolution = Resolution.Daily self.ma_fast = RollingWindow[float]( self.ma_fast_len) # OHLCLoader.get_historical_RollingWindow__last_N_days(float, self.ma_fast_len, self.Log) self.ma_slow = RollingWindow[float]( self.ma_slow_len) # OHLCLoader.get_historical_RollingWindow__last_N_days(float, self.ma_slow_len, self) if prices is not None: for p in prices[-self.ma_fast_len:]: self.ma_fast.Add(p[1][3]) for p in prices[-self.ma_slow_len:]: self.ma_slow.Add(p[1][3]) self.prev_insight_direction = InsightDirection.Flat self.insight_time_span = 0 if resolution == Resolution.Daily: self.insight_time_span = 60 * 24 - 1 elif resolution == Resolution.Hour: self.insight_time_span = 60 - 1 elif resolution == Resolution.Minute: self.insight_time_span = 1 - 0.01 if algorithm is not None: # algorithm.Log(f"self.ma_slow.Count: {self.ma_slow.Count}") algorithm.Log(f"MovingAverage init DONE -> {self.ma_fast_len} / {self.ma_slow_len} ({self.get_ma_fast() } -> { self.get_ma_slow()})") def get_ma_slow(self): if self.ma_slow.Count < self.ma_slow_len: return None return sum(self.ma_slow) / self.ma_slow.Count def get_ma_fast(self): if self.ma_fast.Count < self.ma_fast_len: return None return sum(self.ma_fast) / self.ma_fast.Count def Update(self, algorithm, data): insights = [] period = TimeSpan.FromMinutes(self.insight_time_span) magnitude = 1 close = data["BTCUSD"].Close self.ma_fast.Add(close) self.ma_slow.Add(close) ma_slow = self.get_ma_slow() ma_fast= self.get_ma_fast() if ma_slow is None or ma_fast is None: return [] is_Long = close > ma_slow and close > ma_fast is_Short = close < ma_slow and close < ma_fast direction = self.prev_insight_direction if is_Long: direction = InsightDirection.Up elif is_Short: direction = InsightDirection.Down # algorithm.Log(f"{direction}") insights.append(Insight.Price("BTCUSD", period, direction, magnitude)) algorithm.Log(f"MA Cross {self.ma_fast_len} / {self.ma_slow_len} :: direction == {direction} -> {ma_fast} / {ma_slow}") return insights def OnSecuritiesChanged(self, algorithm, changes): pass
from datetime import datetime, timedelta from pytz import utc UTCMIN = datetime.min.replace(tzinfo=utc) class EqualInsightWeightingPortfolioConstructionModel(PortfolioConstructionModel): def __init__(self, resolution = Resolution.Daily): '''Initialize a new instance of EqualWeightingPortfolioConstructionModel Args: resolution: Rebalancing frequency''' self.insightCollection = InsightCollection() self.removedSymbols = [] self.nextExpiryTime = UTCMIN self.rebalancingTime = UTCMIN self.rebalancingPeriod = Extensions.ToTimeSpan(resolution) def CreateTargets(self, algorithm, insights): '''Create portfolio targets from the specified insights Args: algorithm: The algorithm instance insights: The insights to create portoflio targets from Returns: An enumerable of portoflio targets to be sent to the execution model''' targets = [] if (algorithm.UtcTime <= self.nextExpiryTime and algorithm.UtcTime <= self.rebalancingTime and len(insights) == 0 and self.removedSymbols is None): return targets self.insightCollection.AddRange(insights) # Create flatten target for each security that was removed from the universe if self.removedSymbols is not None: universeDeselectionTargets = [ PortfolioTarget(symbol, 0) for symbol in self.removedSymbols ] targets.extend(universeDeselectionTargets) self.removedSymbols = None # Get insight that haven't expired of each symbol that is still in the universe activeInsights = self.insightCollection.GetActiveInsights(algorithm.UtcTime) # give equal weighting to each insight insight_map = {} for insight in activeInsights: if insight.Symbol not in insight_map: insight_map[insight.Symbol] = {"count": 0, "result": 0} insight_map[insight.Symbol]['count'] += 1 insight_map[insight.Symbol]['result'] += insight.Direction algorithm.Log(f"==================================================") algorithm.Log(f"=============PortfolioConstructionModel===========") algorithm.Log(f"==================================================") algorithm.Log(f"> algorithm.UtcTime:") algorithm.Log(f"> {algorithm.UtcTime}") algorithm.Log(f"> ---------------------") # algorithm.Log(f"==================================================") errorSymbols = {} for symbol in insight_map.keys(): insight_result = insight_map[symbol] # algorithm.Plot("Chart", "Insight", insight_result['result'] / insight_result['count']) target_pct = insight_result['result'] / insight_result['count'] target = PortfolioTarget.Percent(algorithm, symbol, target_pct) algorithm.Log("> target: %s -> %.2f %%" % (symbol, 100 * target_pct)) if not target is None: targets.append(target) else: errorSymbols[insight.Symbol] = insight.Symbol self.nextExpiryTime = self.insightCollection.GetNextExpiryTime() if self.nextExpiryTime is None: self.nextExpiryTime = UTCMIN self.rebalancingTime = algorithm.UtcTime + self.rebalancingPeriod algorithm.Log(f"==================================================") algorithm.Log(f"==========/end PortfolioConstructionModel=========") algorithm.Log(f"==================================================") return targets def OnSecuritiesChanged(self, algorithm, changes): '''Event fired each time the we add/remove securities from the data feed Args: algorithm: The algorithm instance that experienced the change in securities changes: The security additions and removals from the algorithm''' # Get removed symbol and invalidate them in the insight collection self.removedSymbols = [x.Symbol for x in changes.RemovedSecurities] self.insightCollection.Clear(self.removedSymbols)
from clr import AddReference AddReference("System") AddReference("QuantConnect.Common") AddReference("QuantConnect.Algorithm") AddReference("QuantConnect.Algorithm.Framework") from System import * from QuantConnect import * from QuantConnect.Data.Consolidators import * from QuantConnect.Data.Market import * from QuantConnect.Indicators import * from QuantConnect.Orders import * from QuantConnect.Brokerages import * from QuantConnect.Algorithm import * from QuantConnect.Algorithm.Framework import * from QuantConnect.Algorithm.Framework.Alphas import * from QuantConnect.Algorithm.Framework.Execution import * from QuantConnect.Algorithm.Framework.Portfolio import * from QuantConnect.Algorithm.Framework.Risk import * from QuantConnect.Algorithm.Framework.Selection import * from ma_cross_alpha import MovingAverageCrossAlpha from equal_insight_weighting_portfolio_construction import EqualInsightWeightingPortfolioConstructionModel import decimal class CustomFeeModel: def __init__(self, algorithm, custom_fee): self.algorithm = algorithm self.custom_fee = decimal.Decimal(custom_fee) def GetOrderFee(self, security, order): return security.Price * order.AbsoluteQuantity * self.custom_fee ### <summary> ### This demonstration alpha reads the DailyFx calendar and provides insights based upon ### the news' outlook for the root currency's(USD) associated pairs ### </summary> class CustomAlgorithm(QCAlgorithmFramework): def Initialize(self): self.SetStartDate(2015, 1, 1) self.SetEndDate(2019, 1, 1) self.SetCash(100000) self.SetBrokerageModel(BrokerageName.Bitfinex, AccountType.Margin) self.resolution = Resolution.Daily self.symbol_name = "BTCUSD" self.security = self.AddSecurity( SecurityType.Crypto, self.symbol_name, self.resolution, Market.Bitfinex, False, 2.1, False ) # Flag to indicate whether critical error has occurred during strategy execution self.is_error = False # line below returns datetime timedelta for last 30 self.resolution timeframes # Extensions.ToTimeSpan(self.resolution) * 30 tradeBarHistory = self.History([self.security.Symbol], Extensions.ToTimeSpan(self.resolution) * 30, self.resolution) self.prices = list(tradeBarHistory.iterrows()) # remove today's data self.prices = self.prices[:len(self.prices) - 1] self.Log(f"history len - {len(self.prices)}") self.Log(f"history[0] - {self.prices[0]}") self.Log(f"history[-1] - {self.prices[-1]}") self.SetUniverseSelection(ManualUniverseSelectionModel([self.symbol_name])) alpha_list = [] for i in range(8, 12): for j in range(20, 27): alpha_list.append(MovingAverageCrossAlpha(i, j, prices=self.prices, resolution=self.resolution, algorithm=self)) # Set to use our FxCalendar Alpha Model self.SetAlpha( CompositeAlphaModel( *alpha_list ) ) # Default Models For Other Framework Settings self.SetPortfolioConstruction(EqualInsightWeightingPortfolioConstructionModel(resolution=self.resolution)) self.SetExecution(ImmediateExecutionModel()) self.SetRiskManagement(NullRiskManagementModel())