| Overall Statistics |
|
Total Trades 3498 Average Win 0.05% Average Loss -0.05% Compounding Annual Return -0.197% Drawdown 29.200% Expectancy 0.027 Net Profit -0.427% Sharpe Ratio 0.086 Probabilistic Sharpe Ratio 5.305% Loss Rate 48% Win Rate 52% Profit-Loss Ratio 0.97 Alpha -0.004 Beta -0.941 Annual Standard Deviation 0.185 Annual Variance 0.034 Information Ratio 0.098 Tracking Error 0.377 Treynor Ratio -0.017 Total Fees $0.00 Estimated Strategy Capacity $0 Lowest Capacity Asset HSI.HSI 2S Portfolio Turnover 8.26% |
#region imports
from AlgorithmImports import *
#endregion
from datetime import datetime, timedelta
from clr import AddReference
from pytz import timezone
import talib
AddReference("System")
AddReference("QuantConnect.Algorithm")
AddReference("QuantConnect.Common")
from System import *
from QuantConnect import *
from QuantConnect.Algorithm import *
from QuantConnect.Indicators import *
from QuantConnect.Data import BaseData, SubscriptionDataSource, SubscriptionDataConfig
from QuantConnect.Python import PythonData
from QuantConnect.Data.Market import TradeBar
class HSI(PythonData):
def GetSource(self,
config: SubscriptionDataConfig,
date: datetime,
isLive: bool) -> SubscriptionDataSource:
source = "https://raw.githubusercontent.com/antonymawork/Data/main/HK50_1M_HKT.csv"
return SubscriptionDataSource(source, SubscriptionTransportMedium.RemoteFile)
def Reader(self,
config: SubscriptionDataConfig,
line: str,
date: datetime,
isLive: bool) -> BaseData:
# If first character is not digit, pass
if not (line.strip() and line[0].isdigit()):
return None
data = line.split(',')
if data[0].lower() == "date":
return None
hsi = HSI()
hsi.Symbol = config.Symbol
hsi.Time = datetime.strptime(data[0], '%Y-%m-%d %H:%M:%S')
hsi.EndTime = hsi.Time + timedelta(minutes=1)
hsi.Value = float(data[4])
if hsi.Value == 0:
self.Debug("No Value")
return None
hsi["Open"] = float(data[1])
hsi["High"] = float(data[2])
hsi["Low"] = float(data[3])
hsi["Close"] = hsi.Value
hsi["Volume"] = float(data[5])
hsi.Currency = Currencies.HKD
return hsi
class CustomAlgorithm(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2020, 5, 1)
self.SetEndDate(2022, 6, 30)
self.SetAccountCurrency("HKD", 1500000)
self.initial_margin = 101000
self.Debug("Range and Capital Set")
self.symbol = self.AddData(HSI, 'HSI', Resolution.Minute).Symbol
self.SetBenchmark(self.symbol)
self.Debug(f"Symbol: {self.symbol}")
self.ema50 = self.EMA(self.symbol, 55, Resolution.Minute)
self.ema100 = self.EMA(self.symbol, 105, Resolution.Minute)
self.stoch = self.STO(self.symbol, 5, 3, Resolution.Minute)
self.rsi = self.RSI(self.symbol, 5, MovingAverageType.Simple, Resolution.Minute)
self.atr = self.ATR(self.symbol, 3, MovingAverageType.Simple, Resolution.Minute)
self.stochWindow = RollingWindow[IndicatorDataPoint](4)
self.stopMarketTicket = None
# Warmup for 100 minutes
self.SetWarmUp(100, Resolution.Minute)
def OnData(self, slice):
if self.IsWarmingUp:
self.Debug("Warmed Up")
return
if not slice.ContainsKey(self.symbol):
self.Debug(f"Data for {self.symbol} not found in slice")
return
if self.symbol not in slice:
self.Debug("symbol not in slice")
self.Debug(f"Symbol: {slice[self.symbol]}")
return
bar = slice[self.symbol]
#self.Debug(f"Open: {bar['Open']}, High: {bar['High']}, Low: {bar['Low']}, Close: {bar.Value}, Volume: {bar['Volume']}")
close = bar.Close
#self.Debug(f"Close: {close}")
holdings = self.Portfolio[self.symbol].Quantity
#self.Debug(f"Holdings: {holdings}")
self.stochWindow.Add(self.stoch.Current)
long_condition = (
close > self.ema50.Current.Value and
self.ema50.Current.Value > self.ema100.Current.Value and
self.stoch.Current.Value > 20 and self.stochWindow[1].Value < 20 and
self.rsi.Current.Value > 50
)
short_condition = (
close < self.ema50.Current.Value and
self.ema50.Current.Value < self.ema100.Current.Value and
self.stoch.Current.Value < 80 and self.stochWindow[1].Value > 80 and
self.rsi.Current.Value < 50
)
quantity_long = 1
quantity_short = 1
m1 = self.Portfolio.TotalPortfolioValue > quantity_long * self.initial_margin
if long_condition and m1:
self.MarketOrder(self.symbol, quantity_long)
self.stopMarketTicket = self.StopMarketOrder(self.symbol, -quantity_long, round(close - 2 * self.atr.Current.Value, 2))
self.LimitOrder(self.symbol, -quantity_long, round(close + 5 * self.atr.Current.Value, 2))
if short_condition and m1:
self.MarketOrder(self.symbol, quantity_short)
self.stopMarketTicket = self.StopMarketOrder(self.symbol, -quantity_short, round(close + 2 * self.atr.Current.Value, 2))
self.LimitOrder(self.symbol, -quantity_short, round(close - 5 * self.atr.Current.Value, 2))
if self.stopMarketTicket is not None and self.stopMarketTicket.Status == OrderStatus.Filled:
if holdings > 0 and close - 2 * self.atr.Current.Value > self.stopMarketTicket.Get(OrderField.StopPrice):
updateOrderFields = UpdateOrderFields()
updateOrderFields.StopPrice = round(close - 2 * self.atr.Current.Value, 2)
self.stopMarketTicket.Update(updateOrderFields)
elif holdings < 0 and close + 2 * self.atr.Current.Value < self.stopMarketTicket.Get(OrderField.StopPrice):
updateOrderFields = UpdateOrderFields()
updateOrderFields.StopPrice = round(close + 2 * self.atr.Current.Value, 2)
self.stopMarketTicket.Update(updateOrderFields)