| Overall Statistics |
|
Total Orders 910 Average Win 2.69% Average Loss -2.22% Compounding Annual Return 21.322% Drawdown 58.000% Expectancy 0.338 Start Equity 100000 End Equity 1882418.98 Net Profit 1782.419% Sharpe Ratio 0.592 Sortino Ratio 0.731 Probabilistic Sharpe Ratio 2.441% Loss Rate 39% Win Rate 61% Profit-Loss Ratio 1.21 Alpha 0.081 Beta 1.073 Annual Standard Deviation 0.291 Annual Variance 0.084 Information Ratio 0.353 Tracking Error 0.246 Treynor Ratio 0.16 Total Fees $67321.52 Estimated Strategy Capacity $7000.00 Lowest Capacity Asset AHC U02G802FESTH Portfolio Turnover 2.80% |
# region imports
from AlgorithmImports import *
# endregion
from QuantConnect import Resolution
from QuantConnect.Algorithm import QCAlgorithm
import numpy as np
class NCAVsimple(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2010, 5, 1)
#self.SetEndDate(2025,1,1)
self.SetCash(100000) #약 1.3억 = 100K
self.UniverseSettings.Resolution = Resolution.Daily
self.settings.MinimumOrderMarginPortfolioPercentage = 0.01
self.filtered_fine = None
self.filtered_coarse = None
self.symbol = self.AddEquity('SPY', Resolution.Daily).Symbol
self.settings.daily_precise_end_time = False
self.last_month = 0
self.average_valuation_ratios = []
self.should_rebalance = False
self.AddUniverse(self.CoarseSelectionFunction,self.FineSelectionFunction)
self.Schedule.On(self.DateRules.EveryDay(self.symbol),
self.TimeRules.AfterMarketOpen(self.symbol, 10),
self.rebalance)
def CoarseSelectionFunction(self, coarse):
if self.should_rebalance:
self.filtered_coarse = [x.Symbol for x in coarse if (x.HasFundamentalData)
and x.Market == 'usa'
and x.Price > 0.1
and x.DollarVolume>100000]
return self.filtered_coarse
else:
return []
def FineSelectionFunction(self, fine):
if self.should_rebalance:
sorted_by_market_cap = sorted(fine, key = lambda x:x.MarketCap)
fine = [x for x in sorted_by_market_cap[int(len(sorted_by_market_cap)*0.0):int(len(sorted_by_market_cap)*1)]]
fine = [x for x in fine if (float(x.FinancialStatements.BalanceSheet.CurrentAssets.Value) > 0)
and x.FinancialStatements.IncomeStatement.TotalRevenue.Value > 0
# N=Normal (Manufacturing), M=Mining, U=Utility, T=Transportation, B=Bank, I=Insurance
and (x.CompanyReference.IndustryTemplateCode!="B") #은행업 제외
and (x.CompanyReference.IndustryTemplateCode!="I") #보험업 제외
and x.CompanyProfile.HeadquarterCountry == 'USA'
and (float(x.EarningReports.BasicAverageShares.Value) > 0)
and (float(x.FinancialStatements.BalanceSheet.CurrentLiabilities.Value) > 0)
and (float(x.MarketCap) > 0)
and x.OperationRatios.ROIC.ThreeMonths > 0.01 #수익성
and x.OperationRatios.DebtToAssets.Value < 1.0 #재무 건전성
and x.ValuationRatios.FCFRatio > 0.01 #영업 정상?
and x.MarketCap/x.CompanyProfile.EnterpriseValue < 5 #고평가 제외
]
for x in fine:
gross_profits = [
+4*x.FinancialStatements.IncomeStatement.NetIncome.NineMonths,
+4*x.FinancialStatements.IncomeStatement.NetIncome.SixMonths,
+4*x.FinancialStatements.IncomeStatement.NetIncome.ThreeMonths,
]
market_cap = int(x.MarketCap)
averaged_gross_profit = sum(gross_profits)
averaged_net_worth = x.FinancialStatements.BalanceSheet.TotalEquity.Value
# Ensure market_cap is not zero to avoid division by zero
if market_cap > 0:
#DIY valuation formula 10:0.6 = 50:3 ▷ 20:3
ValuationRatio = (3 * averaged_gross_profit + 1 * averaged_net_worth)/ market_cap #+ (np.random.random()-0.5)/3
x.ValuationRatio = ValuationRatio
else:
x.ValuationRatio = -100
fine = [x for x in fine if x.ValuationRatio > 0]
fine = sorted(fine, key=lambda x: x.ValuationRatio, reverse=True)[:5]
self.filtered_fine = [x.Symbol for x in fine]
return self.filtered_fine
else:
return []
def rebalance(self):
# self.should_rebalance = True
# return
if (self.Time.month - self.last_month)%12 == 1 and self.Time.day > 10:
self.should_rebalance = True
self.last_month = self.Time.month
else:
self.should_rebalance = False
def W(self,k_th,length,weight):
n,a,k = length,weight,k_th
return 1/n - a*(k-(n+1)/2)*(2/(n*(n+1)))
def OnData(self, data):
if not self.should_rebalance:
return
stocks_invested = [x.Key for x in self.Portfolio if x.Value.Invested]
for symbol in stocks_invested:
if symbol not in self.filtered_fine:
self.Liquidate(symbol)
if self.filtered_fine:
#weights = [self.W(k,len(self.filtered_fine),0) for k in range(1,len(self.filtered_fine)+1)]
# weights = [round(w,12) for w in weights]
self.Debug(f'{[x.Value for x in self.filtered_fine]}')
for symbol in self.filtered_fine:
self.SetHoldings(symbol, 1/len(self.filtered_fine))
else:
pass
self.should_rebalance = False