avatarAlexzap

Free AI web copilot to create summaries, insights and extended knowledge, download it at here

111683

Abstract

00000.0</span> <span class="hljs-number">302000000.0</span> <span class="hljs-number">221000000.0</span> Pretax Income <span class="hljs-number">2146000000.0</span> <span class="hljs-number">1515000000.0</span> <span class="hljs-number">1552000000.0</span> <span class="hljs-number">1174000000.0</span> Other Income Expense -<span class="hljs-number">96000000.0</span> -<span class="hljs-number">125000000.0</span> -<span class="hljs-number">80000000.0</span> -<span class="hljs-number">101000000.0</span> Other Non Operating Income Expenses <span class="hljs-number">6000000.0</span> <span class="hljs-number">123000000.0</span> <span class="hljs-number">5000000.0</span> <span class="hljs-number">1000000.0</span> Special Income Charges -<span class="hljs-number">82000000.0</span> -<span class="hljs-number">92000000.0</span> -<span class="hljs-number">70000000.0</span> -<span class="hljs-number">90000000.0</span> Gain On Sale Of Ppe NaN <span class="hljs-number">0.0</span> <span class="hljs-number">0.0</span> <span class="hljs-number">50000000.0</span> Gain On Sale Of Business -<span class="hljs-number">24000000.0</span> <span class="hljs-number">0.0</span> <span class="hljs-number">0.0</span> NaN Other Special Charges <span class="hljs-number">4000000.0</span> <span class="hljs-number">14000000.0</span> <span class="hljs-number">21000000.0</span> <span class="hljs-number">65000000.0</span> Write Off <span class="hljs-number">16000000.0</span> <span class="hljs-number">1000000.0</span> <span class="hljs-number">0.0</span> <span class="hljs-number">9000000.0</span> Impairment Of Capital Assets <span class="hljs-number">9000000.0</span> <span class="hljs-number">36000000.0</span> <span class="hljs-number">10000000.0</span> <span class="hljs-number">0.0</span> Restructuring And Mergern Acquisition <span class="hljs-number">29000000.0</span> <span class="hljs-number">41000000.0</span> <span class="hljs-number">39000000.0</span> <span class="hljs-number">66000000.0</span> Earnings From Equity Interest <span class="hljs-number">0.0</span> <span class="hljs-number">18000000.0</span> <span class="hljs-number">5000000.0</span> <span class="hljs-number">3000000.0</span> Gain On Sale Of Security -<span class="hljs-number">20000000.0</span> -<span class="hljs-number">51000000.0</span> -<span class="hljs-number">20000000.0</span> -<span class="hljs-number">15000000.0</span> Net Non Operating Interest Income Expense -<span class="hljs-number">216000000.0</span> -<span class="hljs-number">226000000.0</span> -<span class="hljs-number">208000000.0</span> -<span class="hljs-number">220000000.0</span> Interest Expense Non Operating <span class="hljs-number">249000000.0</span> <span class="hljs-number">240000000.0</span> <span class="hljs-number">215000000.0</span> <span class="hljs-number">233000000.0</span> Interest Income Non Operating <span class="hljs-number">33000000.0</span> <span class="hljs-number">14000000.0</span> <span class="hljs-number">7000000.0</span> <span class="hljs-number">13000000.0</span> Operating Income <span class="hljs-number">2458000000.0</span> <span class="hljs-number">1866000000.0</span> <span class="hljs-number">1840000000.0</span> <span class="hljs-number">1495000000.0</span> Operating Expense <span class="hljs-number">2512000000.0</span> <span class="hljs-number">2363000000.0</span> <span class="hljs-number">2200000000.0</span> <span class="hljs-number">2113000000.0</span> Other Operating Expenses <span class="hljs-number">15000000.0</span> NaN NaN NaN Depreciation Amortization Depletion Income Statement <span class="hljs-number">177000000.0</span> <span class="hljs-number">257000000.0</span> <span class="hljs-number">236000000.0</span> <span class="hljs-number">215000000.0</span> Depreciation And Amortization In Income Statement <span class="hljs-number">177000000.0</span> <span class="hljs-number">257000000.0</span> <span class="hljs-number">236000000.0</span> <span class="hljs-number">215000000.0</span> Amortization <span class="hljs-number">177000000.0</span> <span class="hljs-number">257000000.0</span> <span class="hljs-number">236000000.0</span> <span class="hljs-number">215000000.0</span> Amortization Of Intangibles Income Statement <span class="hljs-number">177000000.0</span> <span class="hljs-number">257000000.0</span> <span class="hljs-number">236000000.0</span> <span class="hljs-number">215000000.0</span> Research And Development <span class="hljs-number">858000000.0</span> <span class="hljs-number">779000000.0</span> <span class="hljs-number">734000000.0</span> <span class="hljs-number">686000000.0</span> Selling General And Administration <span class="hljs-number">1462000000.0</span> <span class="hljs-number">1327000000.0</span> <span class="hljs-number">1230000000.0</span> <span class="hljs-number">1212000000.0</span> General And Administrative Expense <span class="hljs-number">1462000000.0</span> <span class="hljs-number">1327000000.0</span> <span class="hljs-number">1230000000.0</span> <span class="hljs-number">1212000000.0</span> Other Gand A <span class="hljs-number">1561000000.0</span> <span class="hljs-number">1450000000.0</span> <span class="hljs-number">1353000000.0</span> <span class="hljs-number">1293000000.0</span> Salaries And Wages -<span class="hljs-number">99000000.0</span> -<span class="hljs-number">123000000.0</span> -<span class="hljs-number">123000000.0</span> -<span class="hljs-number">81000000.0</span> Gross Profit <span class="hljs-number">4970000000.0</span> <span class="hljs-number">4229000000.0</span> <span class="hljs-number">4040000000.0</span> <span class="hljs-number">3608000000.0</span> Cost Of Revenue <span class="hljs-number">5008000000.0</span> <span class="hljs-number">4883000000.0</span> <span class="hljs-number">4131000000.0</span> <span class="hljs-number">3806000000.0</span> Total Revenue <span class="hljs-number">9978000000.0</span> <span class="hljs-number">9112000000.0</span> <span class="hljs-number">8171000000.0</span> <span class="hljs-number">7414000000.0</span> Operating Revenue <span class="hljs-number">9978000000.0</span> <span class="hljs-number">9112000000.0</span> <span class="hljs-number">8171000000.0</span> <span class="hljs-number">7414000000.0</span></pre></div><div id="61e1"><pre>ticker.cashflow

<span class="hljs-number">2023</span>-<span class="hljs-number">12</span>-<span class="hljs-number">31</span> <span class="hljs-number">2022</span>-<span class="hljs-number">12</span>-<span class="hljs-number">31</span> <span class="hljs-number">2021</span>-<span class="hljs-number">12</span>-<span class="hljs-number">31</span> <span class="hljs-number">2020</span>-<span class="hljs-number">12</span>-<span class="hljs-number">31</span> Free Cash Flow <span class="hljs-number">1791000000.0</span> <span class="hljs-number">1567000000.0</span> <span class="hljs-number">1594000000.0</span> <span class="hljs-number">1396000000.0</span> Repurchase Of Capital Stock -<span class="hljs-number">804000000.0</span> -<span class="hljs-number">836000000.0</span> -<span class="hljs-number">528000000.0</span> -<span class="hljs-number">612000000.0</span> Repayment Of Debt -<span class="hljs-number">1000000.0</span> -<span class="hljs-number">285000000.0</span> -<span class="hljs-number">353000000.0</span> -<span class="hljs-number">1714000000.0</span> Issuance Of Debt <span class="hljs-number">0.0</span> <span class="hljs-number">595000000.0</span> <span class="hljs-number">844000000.0</span> <span class="hljs-number">1692000000.0</span> Issuance Of Capital Stock <span class="hljs-number">104000000.0</span> <span class="hljs-number">156000000.0</span> <span class="hljs-number">102000000.0</span> <span class="hljs-number">108000000.0</span> Capital Expenditure -<span class="hljs-number">253000000.0</span> -<span class="hljs-number">256000000.0</span> -<span class="hljs-number">243000000.0</span> -<span class="hljs-number">217000000.0</span> Interest Paid Supplemental Data <span class="hljs-number">234000000.0</span> <span class="hljs-number">226000000.0</span> <span class="hljs-number">207000000.0</span> <span class="hljs-number">217000000.0</span> Income Tax Paid Supplemental Data <span class="hljs-number">587000000.0</span> <span class="hljs-number">307000000.0</span> <span class="hljs-number">257000000.0</span> <span class="hljs-number">181000000.0</span> End Cash Position <span class="hljs-number">1705000000.0</span> <span class="hljs-number">1325000000.0</span> <span class="hljs-number">1874000000.0</span> <span class="hljs-number">1254000000.0</span> Beginning Cash Position <span class="hljs-number">1325000000.0</span> <span class="hljs-number">1874000000.0</span> <span class="hljs-number">1254000000.0</span> <span class="hljs-number">1001000000.0</span> Effect Of Exchange Rate Changes <span class="hljs-number">45000000.0</span> -<span class="hljs-number">79000000.0</span> -<span class="hljs-number">46000000.0</span> <span class="hljs-number">43000000.0</span> Changes In Cash <span class="hljs-number">335000000.0</span> -<span class="hljs-number">470000000.0</span> <span class="hljs-number">666000000.0</span> <span class="hljs-number">210000000.0</span> Financing Cash Flow -<span class="hljs-number">1295000000.0</span> -<span class="hljs-number">906000000.0</span> -<span class="hljs-number">429000000.0</span> -<span class="hljs-number">966000000.0</span> Cash Flow From Continuing Financing Activities -<span class="hljs-number">1295000000.0</span> -<span class="hljs-number">906000000.0</span> -<span class="hljs-number">429000000.0</span> -<span class="hljs-number">966000000.0</span> Net Other Financing Charges -<span class="hljs-number">5000000.0</span> -<span class="hljs-number">6000000.0</span> -<span class="hljs-number">12000000.0</span> -<span class="hljs-number">4000000.0</span> Cash Dividends Paid -<span class="hljs-number">589000000.0</span> -<span class="hljs-number">530000000.0</span> -<span class="hljs-number">482000000.0</span> -<span class="hljs-number">436000000.0</span> Common Stock Dividend Paid -<span class="hljs-number">589000000.0</span> -<span class="hljs-number">530000000.0</span> -<span class="hljs-number">482000000.0</span> -<span class="hljs-number">436000000.0</span> Net Common Stock Issuance -<span class="hljs-number">700000000.0</span> -<span class="hljs-number">680000000.0</span> -<span class="hljs-number">426000000.0</span> -<span class="hljs-number">504000000.0</span> Common Stock Payments -<span class="hljs-number">804000000.0</span> -<span class="hljs-number">836000000.0</span> -<span class="hljs-number">528000000.0</span> -<span class="hljs-number">612000000.0</span> Common Stock Issuance <span class="hljs-number">104000000.0</span> <span class="hljs-number">156000000.0</span> <span class="hljs-number">102000000.0</span> <span class="hljs-number">108000000.0</span> Net Issuance Payments Of Debt -<span class="hljs-number">1000000.0</span> <span class="hljs-number">310000000.0</span> <span class="hljs-number">491000000.0</span> -<span class="hljs-number">22000000.0</span> Net Short Term Debt Issuance NaN <span class="hljs-number">0.0</span> <span class="hljs-number">0.0</span> <span class="hljs-number">0.0</span> Short Term Debt Payments NaN <span class="hljs-number">0.0</span> <span class="hljs-number">0.0</span> -<span class="hljs-number">800000000.0</span> Short Term Debt Issuance NaN <span class="hljs-number">0.0</span> <span class="hljs-number">0.0</span> <span class="hljs-number">800000000.0</span> Net Long Term Debt Issuance -<span class="hljs-number">1000000.0</span> <span class="hljs-number">310000000.0</span> <span class="hljs-number">491000000.0</span> -<span class="hljs-number">22000000.0</span> Long Term Debt Payments -<span class="hljs-number">1000000.0</span> -<span class="hljs-number">285000000.0</span> -<span class="hljs-number">353000000.0</span> -<span class="hljs-number">914000000.0</span> Long Term Debt Issuance <span class="hljs-number">0.0</span> <span class="hljs-number">595000000.0</span> <span class="hljs-number">844000000.0</span> <span class="hljs-number">892000000.0</span> Investing Cash Flow -<span class="hljs-number">414000000.0</span> -<span class="hljs-number">1387000000.0</span> -<span class="hljs-number">742000000.0</span> -<span class="hljs-number">437000000.0</span> Cash Flow From Continuing Investing Activities -<span class="hljs-number">414000000.0</span> -<span class="hljs-number">1387000000.0</span> -<span class="hljs-number">742000000.0</span> -<span class="hljs-number">437000000.0</span> Net Investment Purchase And Sale <span class="hljs-number">19000000.0</span> <span class="hljs-number">46000000.0</span> <span class="hljs-number">16000000.0</span> <span class="hljs-number">11000000.0</span> Sale Of Investment <span class="hljs-number">19000000.0</span> <span class="hljs-number">46000000.0</span> <span class="hljs-number">16000000.0</span> <span class="hljs-number">11000000.0</span> Net Business Purchase And Sale -<span class="hljs-number">180000000.0</span> -<span class="hljs-number">1177000000.0</span> -<span class="hljs-number">521000000.0</span> -<span class="hljs-number">287000000.0</span> Purchase Of Business -<span class="hljs-number">180000000.0</span> -<span class="hljs-number">1177000000.0</span> -<span class="hljs-number">521000000.0</span> -<span class="hljs-number">287000000.0</span> Net PPE Purchase And Sale <span class="hljs-number">0.0</span> <span class="hljs-number">0.0</span> <span class="hljs-number">6000000.0</span> <span class="hljs-number">56000000.0</span> Sale Of PPE <span class="hljs-number">0.0</span> <span class="hljs-number">0.0</span> <span class="hljs-number">6000000.0</span> <span class="hljs-number">56000000.0</span> Capital Expenditure Reported -<span class="hljs-number">253000000.0</span> -<span class="hljs-number">256000000.0</span> -<span class="hljs-number">243000000.0</span> -<span class="hljs-number">217000000.0</span> Operating Cash Flow <span class="hljs-number">2044000000.0</span> <span class="hljs-number">1823000000.0</span> <span class="hljs-number">1837000000.0</span> <span class="hljs-number">1613000000.0</span> Cash Flow From Continuing Operating Activities <span class="hljs-number">2044000000.0</span> <span class="hljs-number">1823000000.0</span> <span class="hljs-number">1837000000.0</span> <span class="hljs-number">1613000000.0</span> Change In Working Capital -<span class="hljs-number">276000000.0</span> -<span class="hljs-number">329000000.0</span> <span class="hljs-number">0.0</span> <span class="hljs-number">102000000.0</span> Change In Other Working Capital -<span class="hljs-number">70000000.0</span> -<span class="hljs-number">425000000.0</span> -<span class="hljs-number">92000000.0</span> -<span class="hljs-number">25000000.0</span> Change In Other Current Assets -<span class="hljs-number">82000000.0</span> -<span class="hljs-number">1000000.0</span> -<span class="hljs-number">205000000.0</span> <span class="hljs-number">167000000.0</span> Change In Payables And Accrued Expense -<span class="hljs-number">144000000.0</span> <span class="hljs-number">451000000.0</span> <span class="hljs-number">578000000.0</span> -<span class="hljs-number">116000000.0</span> Change In Payable -<span class="hljs-number">144000000.0</span> <span class="hljs-number">451000000.0</span> <span class="hljs-number">578000000.0</span> -<span class="hljs-number">116000000.0</span> Change In Account Payable -<span class="hljs-number">144000000.0</span> <span class="hljs-number">451000000.0</span> <span class="hljs-number">578000000.0</span> -<span class="hljs-number">116000000.0</span> Change In Inventory <span class="hljs-number">200000000.0</span> -<span class="hljs-number">242000000.0</span> -<span class="hljs-number">284000000.0</span> -<span class="hljs-number">14000000.0</span> Change In Receivables -<span class="hljs-number">180000000.0</span> -<span class="hljs-number">112000000.0</span> <span class="hljs-number">3000000.0</span> <span class="hljs-number">90000000.0</span> Changes In Account Receivables -<span class="hljs-number">180000000.0</span> -<span class="hljs-number">112000000.0</span> <span class="hljs-number">3000000.0</span> <span class="hljs-number">90000000.0</span> Other Non Cash Items <span class="hljs-number">38000000.0</span> <span class="hljs-number">23000000.0</span> <span class="hljs-number">3000000.0</span> -<span class="hljs-number">13000000.0</span> Stock Based Compensation <span class="hljs-number">212000000.0</span> <span class="hljs-number">172000000.0</span> <span class="hljs-number">129000000.0</span> <span class="hljs-number">129000000.0</span> Asset Impairment Charge <span class="hljs-number">0.0</span> <span class="hljs-number">147000000.0</span> <span class="hljs-number">0.0</span> NaN Deferred Tax NaN NaN <span class="hljs-number">34000000.0</span> -<span class="hljs-number">25000000.0</span> Deferred Income Tax NaN NaN <span class="hljs-number">34000000.0</span> -<span class="hljs-number">25000000.0</span> Depreciation Amortization Depletion <span class="hljs-number">356000000.0</span> <span class="hljs-number">440000000.0</span> <span class="hljs-number">438000000.0</span> <span class="hljs-number">409000000.0</span> Depreciation And Amortization <span class="hljs-number">356000000.0</span> <span class="hljs-number">440000000.0</span> <span class="hljs-number">438000000.0</span> <span class="hljs-number">409000000.0</span> Operating Gains Losses NaN <span class="hljs-number">3000000.0</span> <span class="hljs-number">17000000.0</span> <span class="hljs-number">58000000.0</span> Pension And Employee Benefit Expense NaN NaN <span class="hljs-number">0.0</span> <span class="hljs-number">0.0</span> Gain Loss On Investment Securities NaN -<span class="hljs-number">3000000.0</span> -<span class="hljs-number">1000000.0</span> <span class="hljs-number">2000000.0</span> Net Income From Continuing Operations <span class="hljs-number">1714000000.0</span> <span class="hljs-number">1367000000.0</span> <span class="hljs-number">1250000000.0</span> <span class="hljs-number">953000000.0</span></pre></div><ul><li>Fetching the INTC current market cap, annual financials, and cashflow</li></ul><div id="f8c7"><pre>ticker = yf.Ticker(<span class="hljs-string">'INTC'</span>) current_market_cap = ticker.info[<span class="hljs-string">'marketCap'</span>] <span class="hljs-built_in">print</span>(current_market_cap) <span class="hljs-number">149054291968</span>

ticker.financials

<span class="hljs-number">2023</span>-<span class="hljs-number">12</span>-<span class="hljs-number">31</span> <span class="hljs-number">2022</span>-<span class="hljs-number">12</span>-<span class="hljs-number">31</span> <span class="hljs-number">2021</span>-<span class="hljs-number">12</span>-<span class="hljs-number">31</span> <span class="hljs-number">2020</span>-<span class="hljs-number">12</span>-<span class="hljs-number">31</span> Tax Effect Of Unusual Items -<span class="hljs-number">20502000.0</span> -<span class="hljs-number">14014000.0</span> -<span class="hljs-number">17550000.0</span> -<span class="hljs-number">19740000.0</span> Tax Rate For Calcs <span class="hljs-number">0.201</span> <span class="hljs-number">0.098</span> <span class="hljs-number">0.195</span> <span class="hljs-number">0.188</span> Normalized EBITDA <span class="hljs-number">2853000000.0</span> <span class="hljs-number">2338000000.0</span> <span class="hljs-number">2295000000.0</span> <span class="hljs-number">1921000000.0</span> Total Unusual Items -<span class="hljs-number">102000000.0</span> -<span class="hljs-number">143000000.0</span> -<span class="hljs-number">90000000.0</span> -<span class="hljs-number">105000000.0</span> Total Unusual Items Excluding Goodwill -<span class="hljs-number">102000000.0</span> -<span class="hljs-number">143000000.0</span> -<span class="hljs-number">90000000.0</span> -<span class="hljs-number">105000000.0</span> Net Income From Continuing Operation Net Minority Interest <span class="hljs-number">1709000000.0</span> <span class="hljs-number">1363000000.0</span> <span class="hljs-number">1245000000.0</span> <span class="hljs-number">949000000.0</span> Reconciled Depreciation <span class="hljs-number">356000000.0</span> <span class="hljs-number">440000000.0</span> <span class="hljs-number">438000000.0</span> <span class="hljs-number">409000000.0</span> Reconciled Cost Of Revenue <span class="hljs-number">4829000000.0</span> <span class="hljs-number">4700000000.0</span> <span class="hljs-number">3929000000.0</span> <span class="hljs-number">3612000000.0</span> EBITDA <span class="hljs-number">2751000000.0</span> <span class="hljs-number">2195000000.0</span> <span class="hljs-number">2205000000.0</span> <span class="hljs-number">1816000000.0</span> EBIT <span class="hljs-number">2395000000.0</span> <span class="hljs-number">1755000000.0</span> <span class="hljs-number">1767000000.0</span> <span class="hljs-number">1407000000.0</span> Net Interest Income -<span class="hljs-number">216000000.0</span> -<span class="hljs-number">226000000.0</span> -<span class="hljs-number">208000000.0</span> -<span class="hljs-number">220000000.0</span> Interest Expense <span class="hljs-number">249000000.0</span> <span class="hljs-number">240000000.0</span> <span class="hljs-number">215000000.0</span> <span class="hljs-number">233000000.0</span> Interest Income <span class="hljs-number">33000000.0</span> <span class="hljs-number">14000000.0</span> <span class="hljs-number">7000000.0</span> <span class="hljs-number">13000000.0</span> Normalized Income <span class="hljs-number">1790498000.0</span> <span class="hljs-number">1491986000.0</span> <span class="hljs-number">1317450000.0</span> <span class="hljs-number">1034260000.0</span> Net Income From Continuing And Discontinued Operation <span class="hljs-number">1709000000.0</span> <span class="hljs-number">1363000000.0</span> <span class="hljs-number">1245000000.0</span> <span class="hljs-number">949000000.0</span> Total Expenses <span class="hljs-number">7520000000.0</span> <span class="hljs-number">7246000000.0</span> <span class="hljs-number">6331000000.0</span> <span class="hljs-number">5919000000.0</span> Total Operating Income As Reported <span class="hljs-number">2294000000.0</span> <span class="hljs-number">1661000000.0</span> <span class="hljs-number">1667000000.0</span> <span class="hljs-number">1383000000.0</span> Diluted Average Shares NaN <span class="hljs-number">171900000.0</span> <span class="hljs-number">173600000.0</span> <span class="hljs-number">174100000.0</span> Basic Average Shares NaN <span class="hljs-number">167500000.0</span> <span class="hljs-number">169200000.0</span> <span class="hljs-number">170000000.0</span> Diluted EPS NaN <span class="hljs-number">7.93</span> <span class="hljs-number">7.17</span> <span class="hljs-number">5.45</span> Basic EPS NaN <span class="hljs-number">8.14</span> <span class="hljs-number">7.36</span> <span class="hljs-number">5.58</span> Diluted NI Availto Com Stockholders <span class="hljs-number">1709000000.0</span> <span class="hljs-number">1363000000.0</span> <span class="hljs-number">1245000000.0</span> <span class="hljs-number">949000000.0</span> Net Income Common Stockholders <span class="hljs-number">1709000000.0</span> <span class="hljs-number">1363000000.0</span> <span class="hljs-number">1245000000.0</span> <span class="hljs-number">949000000.0</span> Net Income <span class="hljs-number">1709000000.0</span> <span class="hljs-number">1363000000.0</span> <span class="hljs-number">1245000000.0</span> <span class="hljs-number">949000000.0</span> Minority Interests -<span class="hljs-number">5000000.0</span> -<span class="hljs-number">4000000.0</span> -<span class="hljs-number">5000000.0</span> -<span class="hljs-number">4000000.0</span> Net Income Including Noncontrolling Interests <span class="hljs-number">1714000000.0</span> <span class="hljs-number">1367000000.0</span> <span class="hljs-number">1250000000.0</span> <span class="hljs-number">953000000.0</span> Net Income Continuous Operations <span class="hljs-number">1714000000.0</span> <span class="hljs-number">1367000000.0</span> <span class="hljs-number">1250000000.0</span> <span class="hljs-number">953000000.0</span> Tax Provision <span class="hljs-number">432000000.0</span> <span class="hljs-number">148000000.0</span> <span class="hljs-number">302000000.0</span> <span class="hljs-number">221000000.0</span> Pretax Income <span class="hljs-number">2146000000.0</span> <span class="hljs-number">1515000000.0</span> <span class="hljs-number">1552000000.0</span> <span class="hljs-number">1174000000.0</span> Other Income Expense -<span class="hljs-number">96000000.0</span> -<span class="hljs-number">125000000.0</span> -<span class="hljs-number">80000000.0</span> -<span class="hljs-number">101000000.0</span> Other Non Operating Income Expenses <span class="hljs-number">6000000.0</span> <span class="hljs-number">123000000.0</span> <span class="hljs-number">5000000.0</span> <span class="hljs-number">1000000.0</span> Special Income Charges -<span class="hljs-number">82000000.0</span> -<span class="hljs-number">92000000.0</span> -<span class="hljs-number">70000000.0</span> -<span class="hljs-number">90000000.0</span> Gain On Sale Of Ppe NaN <span class="hljs-number">0.0</span> <span class="hljs-number">0.0</span> <span class="hljs-number">50000000.0</span> Gain On Sale Of Business -<span class="hljs-number">24000000.0</span> <span class="hljs-number">0.0</span> <span class="hljs-number">0.0</span> NaN Other Special Charges <span class="hljs-number">4000000.0</span> <span class="hljs-number">14000000.0</span> <span class="hljs-number">21000000.0</span> <span class="hljs-number">65000000.0</span> Write Off <span class="hljs-number">16000000.0</span> <span class="hljs-number">1000000.0</span> <span class="hljs-number">0.0</span> <span class="hljs-number">9000000.0</span> Impairment Of Capital Assets <span class="hljs-number">9000000.0</span> <span class="hljs-number">36000000.0</span> <span class="hljs-number">10000000.0</span> <span class="hljs-number">0.0</span> Restructuring And Mergern Acquisition <span class="hljs-number">29000000.0</span> <span class="hljs-number">41000000.0</span> <span class="hljs-number">39000000.0</span> <span class="hljs-number">66000000.0</span> Earnings From Equity Interest <span class="hljs-number">0.0</span> <span class="hljs-number">18000000.0</span> <span class="hljs-number">5000000.0</span> <span class="hljs-number">3000000.0</span> Gain On Sale Of Security -<span class="hljs-number">20000000.0</span> -<span class="hljs-number">51000000.0</span> -<span class="hljs-number">20000000.0</span> -<span class="hljs-number">15000000.0</span> Net Non Operating Interest Income Expense -<span class="hljs-number">216000000.0</span> -<span class="hljs-number">226000000.0</span> -<span class="hljs-number">208000000.0</span> -<span class="hljs-number">220000000.0</span> Interest Expense Non Operating <span class="hljs-number">249000000.0</span> <span class="hljs-number">240000000.0</span> <span class="hljs-number">215000000.0</span> <span class="hljs-number">233000000.0</span> Interest Income Non Operating <span class="hljs-number">33000000.0</span> <span class="hljs-number">14000000.0</span> <span class="hljs-number">7000000.0</span> <span class="hljs-number">13000000.0</span> Operating Income <span class="hljs-number">2458000000.0</span> <span class="hljs-number">1866000000.0</span> <span class="hljs-number">1840000000.0</span> <span class="hljs-number">1495000000.0</span> Operating Expense <span class="hljs-number">2512000000.0</span> <span class="hljs-number">2363000000.0</span> <span class="hljs-number">2200000000.0</span> <span class="hljs-number">2113000000.0</span> Other Operating Expenses <span class="hljs-number">15000000.0</span> NaN NaN NaN Depreciation Amortization Depletion Income Statement <span class="hljs-number">177000000.0</span> <span class="hljs-number">257000000.0</span> <span class="hljs-number">236000000.0</span> <span class="hljs-number">215000000.0</span> Depreciation And Amortization In Income Statement <span class="hljs-number">177000000.0</span> <span class="hljs-number">257000000.0</span> <span class="hljs-number">236000000.0</span> <span class="hljs-number">215000000.0</span> Amortization <span class="hljs-number">177000000.0</span> <span class="hljs-number">257000000.0</span> <span class="hljs-number">236000000.0</span> <span class="hljs-number">215000000.0</span> Amortization Of Intangibles Income Statement <span class="hljs-number">177000000.0</span> <span class="hljs-number">257000000.0</span> <span class="hljs-number">236000000.0</span> <span class="hljs-number">215000000.0</span> Research And Development <span class="hljs-number">858000000.0</span> <span class="hljs-number">779000000.0</span> <span class="hljs-number">734000000.0</span> <span class="hljs-number">686000000.0</span> Selling General And Administration <span class="hljs-number">1462000000.0</span> <span class="hljs-number">1327000000.0</span> <span class="hljs-number">1230000000.0</span> <span class="hljs-number">1212000000.0</span> General And Administrative Expense <span class="hljs-number">1462000000.0</span> <span class="hljs-number">1327000000.0</span> <span class="hljs-number">1230000000.0</span> <span class="hljs-number">1212000000.0</span> Other Gand A <span class="hljs-number">1561000000.0</span> <span class="hljs-number">1450000000.0</span> <span class="hljs-number">1353000000.0</span> <span class="hljs-number">1293000000.0</span> Salaries And Wages -<span class="hljs-number">99000000.0</span> -<span class="hljs-number">123000000.0</span> -<span class="hljs-number">123000000.0</span> -<span class="hljs-number">81000000.0</span> Gross Profit <span class="hljs-number">4970000000.0</span> <span class="hljs-number">4229000000.0</span> <span class="hljs-number">4040000000.0</span> <span class="hljs-number">3608000000.0</span> Cost Of Revenue <span class="hljs-number">5008000000.0</span> <span class="hljs-number">4883000000.0</span> <span class="hljs-number">4131000000.0</span> <span class="hljs-number">3806000000.0</span> Total Revenue <span class="hljs-number">9978000000.0</span> <span class="hljs-number">9112000000.0</span> <span class="hljs-number">8171000000.0</span> <span class="hljs-number">7414000000.0</span> Operating Revenue <span class="hljs-number">9978000000.0</span> <span class="hljs-number">9112000000.0</span> <span class="hljs-number">8171000000.0</span> <span class="hljs-number">7414000000.0</span></pre></div><div id="0766"><pre>ticker.cashflow

<span class="hljs-number">2023</span>-<span class="hljs-number">12</span>-<span class="hljs-number">31</span> <span class="hljs-number">2022</span>-<span class="hljs-number">12</span>-<span class="hljs-number">31</span> <span class="hljs-number">2021</span>-<span class="hljs-number">12</span>-<span class="hljs-number">31</span> <span class="hljs-number">2020</span>-<span class="hljs-number">12</span>-<span class="hljs-number">31</span> Free Cash Flow <span class="hljs-number">1791000000.0</span> <span class="hljs-number">1567000000.0</span> <span class="hljs-number">1594000000.0</span> <span class="hljs-number">1396000000.0</span> Repurchase Of Capital Stock -<span class="hljs-number">804000000.0</span> -<span class="hljs-number">836000000.0</span> -<span class="hljs-number">528000000.0</span> -<span class="hljs-number">612000000.0</span> Repayment Of Debt -<span class="hljs-number">1000000.0</span> -<span class="hljs-number">285000000.0</span> -<span class="hljs-number">353000000.0</span> -<span class="hljs-number">1714000000.0</span> Issuance Of Debt <span class="hljs-number">0.0</span> <span class="hljs-number">595000000.0</span> <span class="hljs-number">844000000.0</span> <span class="hljs-number">1692000000.0</span> Issuance Of Capital Stock <span class="hljs-number">104000000.0</span> <span class="hljs-number">156000000.0</span> <span class="hljs-number">102000000.0</span> <span class="hljs-number">108000000.0</span> Capital Expenditure -<span class="hljs-number">253000000.0</span> -<span class="hljs-number">256000000.0</span> -<span class="hljs-number">243000000.0</span> -<span class="hljs-number">217000000.0</span> Interest Paid Supplemental Data <span class="hljs-number">234000000.0</span> <span class="hljs-number">226000000.0</span> <span class="hljs-number">207000000.0</span> <span class="hljs-number">217000000.0</span> Income Tax Paid Supplemental Data <span class="hljs-number">587000000.0</span> <span class="hljs-number">307000000.0</span> <span class="hljs-number">257000000.0</span> <span class="hljs-number">181000000.0</span> End Cash Position <span class="hljs-number">1705000000.0</span> <span class="hljs-number">1325000000.0</span> <span class="hljs-number">1874000000.0</span> <span class="hljs-number">1254000000.0</span> Beginning Cash Position <span class="hljs-number">1325000000.0</span> <span class="hljs-number">1874000000.0</span> <span class="hljs-number">1254000000.0</span> <span class="hljs-number">1001000000.0</span> Effect Of Exchange Rate Changes <span class="hljs-number">45000000.0</span> -<span class="hljs-number">79000000.0</span> -<span class="hljs-number">46000000.0</span> <span class="hljs-number">43000000.0</span> Changes In Cash <span class="hljs-number">335000000.0</span> -<span class="hljs-number">470000000.0</span> <span class="hljs-number">666000000.0</span> <span class="hljs-number">210000000.0</span> Financing Cash Flow -<span class="hljs-number">1295000000.0</span> -<span class="hljs-number">906000000.0</span> -<span class="hljs-number">429000000.0</span> -<span class="hljs-number">966000000.0</span> Cash Flow From Continuing Financing Activities -<span class="hljs-number">1295000000.0</span> -<span class="hljs-number">906000000.0</span> -<span class="hljs-number">429000000.0</span> -<span class="hljs-number">966000000.0</span> Net Other Financing Charges -<span class="hljs-number">5000000.0</span> -<span class="hljs-number">6000000.0</span> -<span class="hljs-number">12000000.0</span> -<span class="hljs-number">4000000.0</span> Cash Dividends Paid -<span class="hljs-number">589000000.0</span> -<span class="hljs-number">530000000.0</span> -<span class="hljs-number">482000000.0</span> -<span class="hljs-number">436000000.0</span> Common Stock Dividend Paid -<span class="hljs-number">589000000.0</span> -<span class="hljs-number">530000000.0</span> -<span class="hljs-number">482000000.0</span> -<span class="hljs-number">436000000.0</span> Net Common Stock Issuance -<span class="hljs-number">700000000.0</span> -<span class="hljs-number">680000000.0</span> -<span class="hljs-number">426000000.0</span> -<span class="hljs-number">504000000.0</span> Common Stock Payments -<span class="hljs-number">804000000.0</span> -<span class="hljs-number">836000000.0</span> -<span class="hljs-number">528000000.0</span> -<span class="hljs-number">612000000.0</span> Common Stock Issuance <span class="hljs-number">104000000.0</span> <span class="hljs-number">156000000.0</span> <span class="hljs-number">102000000.0</span> <span class="hljs-number">108000000.0</span> Net Issuance Payments Of Debt -<span class="hljs-number">1000000.0</span> <span class="hljs-number">310000000.0</span> <span class="hljs-number">491000000.0</span> -<span class="hljs-number">22000000.0</span> Net Short Term Debt Issuance NaN <span class="hljs-number">0.0</span> <span class="hljs-number">0.0</span> <span class="hljs-number">0.0</span> Short Term Debt Payments NaN <span class="hljs-number">0.0</span> <span class="hljs-number">0.0</span> -<span class="hljs-number">800000000.0</span> Short Term Debt Issuance NaN <span class="hljs-number">0.0</span> <span class="hljs-number">0.0</span> <span class="hljs-number">800000000.0</span> Net Long Term Debt Issuance -<span class="hljs-number">1000000.0</span> <span class="hljs-number">310000000.0</span> <span class="hljs-number">491000000.0</span> -<span class="hljs-number">22000000.0</span> Long Term Debt Payments -<span class="hljs-number">1000000.0</span> -<span class="hljs-number">285000000.0</span> -<span class="hljs-number">353000000.0</span> -<span class="hljs-number">914000000.0</span> Long Term Debt Issuance <span class="hljs-number">0.0</span> <span class="hljs-number">595000000.0</span> <span class="hljs-number">844000000.0</span> <span class="hljs-number">892000000.0</span> Investing Cash Flow -<span class="hljs-number">414000000.0</span> -<span class="hljs-number">1387000000.0</span> -<span class="hljs-number">742000000.0</span> -<span class="hljs-number">437000000.0</span> Cash Flow From Continuing Investing Activities -<span class="hljs-number">414000000.0</span> -<span class="hljs-number">1387000000.0</span> -<span class="hljs-number">742000000.0</span> -<span class="hljs-number">437000000.0</span> Net Investment Purchase And Sale <span class="hljs-number">19000000.0</span> <span class="hljs-number">46000000.0</span> <span class="hljs-number">16000000.0</span> <span class="hljs-number">11000000.0</span> Sale Of Investment <span class="hljs-number">19000000.0</span> <span class="hljs-number">46000000.0</span> <span class="hljs-number">16000000.0</span> <span class="hljs-number">11000000.0</span> Net Business Purchase And Sale -<span class="hljs-number">180000000.0</span> -<span class="hljs-number">1177000000.0</span> -<span class="hljs-number">521000000.0</span> -<span class="hljs-number">287000000.0</span> Purchase Of Business -<span class="hljs-number">180000000.0</span> -<span class="hljs-number">1177000000.0</span> -<span class="hljs-number">521000000.0</span> -<span class="hljs-number">287000000.0</span> Net PPE Purchase And Sale <span class="hljs-number">0.0</span> <span class="hljs-number">0.0</span> <span class="hljs-number">6000000.0</span> <span class="hljs-number">56000000.0</span> Sale Of PPE <span class="hljs-number">0.0</span> <span class="hljs-number">0.0</span> <span class="hljs-number">6000000.0</span> <span class="hljs-number">56000000.0</span> Capital Expenditure Reported -<span class="hljs-number">253000000.0</span> -<span class="hljs-number">256000000.0</span> -<span class="hljs-number">243000000.0</span> -<span class="hljs-number">217000000.0</span> Operating Cash Flow <span class="hljs-number">2044000000.0</span> <span class="hljs-number">1823000000.0</span> <span class="hljs-number">1837000000.0</span> <span class="hljs-number">1613000000.0</span> Cash Flow From Continuing Operating Activities <span class="hljs-number">2044000000.0</span> <span class="hljs-number">1823000000.0</span> <span class="hljs-number">1837000000.0</span> <span class="hljs-number">1613000000.0</span> Change In Working Capital -<span class="hljs-number">276000000.0</span> -<span class="hljs-number">329000000.0</span> <span class="hljs-number">0.0</span> <span class="hljs-number">102000000.0</span> Change In Other Working Capital -<span class="hljs-number">70000000.0</span> -<span class="hljs-number">425000000.0</span> -<span class="hljs-number">92000000.0</span> -<span class="hljs-number">25000000.0</span> Change In Other Current Assets -<span class="hljs-number">82000000.0</span> -<span class="hljs-number">1000000.0</span> -<span class="hljs-number">205000000.0</span> <span class="hljs-number">167000000.0</span> Change In Payables And Accrued Expense -<span class="hljs-number">144000000.0</span> <span class="hljs-number">451000000.0</span> <span class="hljs-number">578000000.0</span> -<span class="hljs-number">116000000.0</span> Change In Payable -<span class="hljs-number">144000000.0</span> <span class="hljs-number">451000000.0</span> <span class="hljs-number">578000000.0</span> -<span class="hljs-number">116000000.0</span> Change In Account Payable -<span class="hljs-number">144000000.0</span> <span class="hljs-number">451000000.0</span> <span class="hljs-number">578000000.0</span> -<span class="hljs-number">116000000.0</span> Change In Inventory <span class="hljs-number">200000000.0</span> -<span class="hljs-number">242000000.0</span> -<span class="hljs-number">284000000.0</span> -<span class="hljs-number">14000000.0</span> Change In Receivables -<span class="hljs-number">180000000.0</span> -<span class="hljs-number">112000000.0</span> <span class="hljs-number">3000000.0</span> <span class="hljs-number">90000000.0</span> Changes In Account Receivables -<span class="hljs-number">180000000.0</span> -<span class="hljs-number">112000000.0</span> <span class="hljs-number">3000000.0</span> <span class="hljs-number">90000000.0</span> Other Non Cash Items <span class="hljs-number">38000000.0</span> <span class="hljs-number">23000000.0</span> <span class="hljs-number">3000000.0</span> -<span class="hljs-number">13000000.0</span> Stock Based Compensation <span class="hljs-number">212000000.0</span> <span class="hljs-number">172000000.0</span> <span class="hljs-number">129000000.0</span> <span class="hljs-number">129000000.0</span> Asset Impairment Charge <span class="hljs-number">0.0</span> <span class="hljs-number">147000000.0</span> <span class="hljs-number">0.0</span> NaN Deferred Tax NaN NaN <span class="hljs-number">34000000.0</span> -<span class="hljs-number">25000000.0</span> Deferred Income Tax NaN NaN <span class="hljs-number">34000000.0</span> -<span class="hljs-number">25000000.0</span> Depreciation Amortization Depletion <span class="hljs-number">356000000.0</span> <span class="hljs-number">440000000.0</span> <span class="hljs-number">438000000.0</span> <span class="hljs-number">409000000.0</span> Depreciation And Amortization <span class="hljs-number">356000000.0</span> <span class="hljs-number">440000000.0</span> <span class="hljs-number">438000000.0</span> <span class="hljs-number">409000000.0</span> Operating Gains Losses NaN <span class="hljs-number">3000000.0</span> <span class="hljs-number">17000000.0</span> <span class="hljs-number">58000000.0</span> Pension And Employee Benefit Expense NaN NaN <span class="hljs-number">0.0</span> <span class="hljs-number">0.0</span> Gain Loss On Investment Securities NaN -<span class="hljs-number">3000000.0</span> -<span class="hljs-number">1000000.0</span> <span class="hljs-number">2000000.0</span> Net Income From Continuing Operations <span class="hljs-number">1714000000.0</span> <span class="hljs-number">1367000000.0</span> <span class="hljs-number">1250000000.0</span> <span class="hljs-number">953000000.0</span></pre></div><h2 id="eb05">Stock Fundamentals</h2><ul><li>Extracting the top 3 stock fundamentals: EPS, P/E, and ROE</li></ul><div id="aa7c"><pre><span class="hljs-comment"># Getting NVDA data</span> nvda1 = yf.Ticker(<span class="hljs-string">"NVDA"</span>) nvda_eps = nvda1.info[<span class="hljs-string">'trailingEps'</span>] nvda_pe_ratio = nvda1.info[<span class="hljs-string">'trailingPE'</span>] nvda_roe = nvda1.info[<span class="hljs-string">'returnOnEquity'</span>]*<span class="hljs-number">100</span> <span class="hljs-built_in">print</span>(nvda_eps) <span class="hljs-built_in">print</span>(nvda_pe_ratio) <span class="hljs-built_in">print</span>(nvda_roe) <span class="hljs-built_in">print</span>(nvda1.info) <span class="hljs-comment">#Print general company info</span>

<span class="hljs-number">11.96</span> <span class="hljs-number">63.712376</span> <span class="hljs-number">91.458</span>

<span class="hljs-comment"># Getting AMD data</span> nvda1 = yf.Ticker(<span class="hljs-string">"AMD"</span>) nvda_eps = nvda1.info[<span class="hljs-string">'trailingEps'</span>] nvda_pe_ratio = nvda1.info[<span class="hljs-string">'trailingPE'</span>] nvda_roe = nvda1.info[<span class="hljs-string">'returnOnEquity'</span>]*<span class="hljs-number">100</span> <span class="hljs-built_in">print</span>(nvda1.info) <span class="hljs-comment">#Print general company info</span> <span class="hljs-number">0.53</span> <span class="hljs-number">276.67926</span> <span class="hljs-number">1.544</span>

<span class="hljs-comment"># Getting INTC data</span> nvda1 = yf.Ticker(<span class="hljs-string">"INTC"</span>) nvda_eps = nvda1.info[<span class="hljs-string">'trailingEps'</span>] nvda_pe_ratio = nvda1.info[<span class="hljs-string">'trailingPE'</span>] nvda_roe = nvda1.info[<span class="hljs-string">'returnOnEquity'</span>]*<span class="hljs-number">100</span> <span class="hljs-built_in">print</span>(nvda_eps) <span class="hljs-built_in">print</span>(nvda_pe_ratio) <span class="hljs-built_in">print</span>(nvda_roe) <span class="hljs-built_in">print</span>(nvda1.info) <span class="hljs-comment">#Print general company info</span> <span class="hljs-number">0.4</span> <span class="hljs-number">85.5</span> <span class="hljs-number">1.5709999999999997</span>

<span class="hljs-comment"># Getting MSI data</span> nvda1 = yf.Ticker(<span class="hljs-string">"MSI"</span>) nvda_eps = nvda1.info[<span class="hljs-string">'trailingEps'</span>] nvda_pe_ratio = nvda1.info[<span class="hljs-string">'trailingPE'</span>] nvda_roe = nvda1.info[<span class="hljs-string">'returnOnEquity'</span>]*<span class="hljs-number">100</span> <span class="hljs-built_in">print</span>(nvda_eps) <span class="hljs-built_in">print</span>(nvda_pe_ratio) <span class="hljs-built_in">print</span>(nvda_roe) <span class="hljs-built_in">print</span>(nvda1.info) <span class="hljs-comment">#Print general company info</span> <span class="hljs-number">9.92</span> <span class="hljs-number">34.23891</span> <span class="hljs-number">394.02301</span></pre></div><ul><li>Checking debtToEquity, revenuePerShare, pegRatio, and revenueGrowth</li></ul><div id="eea3"><pre><span class="hljs-comment">#AMD</span>

nvda1 = yf.Ticker(<span class="hljs-string">"AMD"</span>) nv_rev_growth = nvda1.info[<span class="hljs-string">'revenueGrowth'</span>] nv_debt_equity = nvda1.info[<span class="hljs-string">'debtToEquity'</span>] nv_rev_share = nvda1.info[<span class="hljs-string">'revenuePerShare'</span>] nv_peg_ratio = nvda1.info[<span class="hljs-string">'pegRatio'</span>] <span class="hljs-built_in">print</span>(nv_rev_growth) <span class="hljs-built_in">print</span>(nv_debt_equity) <span class="hljs-built_in">print</span>(nv_rev_share) <span class="hljs-built_in">print</span>(nv_peg_ratio) <span class="hljs-number">0.102</span> <span class="hljs-number">5.563</span> <span class="hljs-number">14.052</span> <span class="hljs-number">1.94</span>

<span class="hljs-comment">#INTC</span>

nvda1 = yf.Ticker(<span class="hljs-string">"INTC"</span>) nv_rev_growth = nvda1.info[<span class="hljs-string">'revenueGrowth'</span>] nv_debt_equity = nvda1.info[<span class="hljs-string">'debtToEquity'</span>] nv_rev_share = nvda1.info[<span class="hljs-string">'revenuePerShare'</span>] nv_peg_ratio = nvda1.info[<span class="hljs-string">'pegRatio'</span>] <span class="hljs-built_in">print</span>(nv_rev_growth) <span class="hljs-built_in">print</span>(nv_debt_equity) <span class="hljs-built_in">print</span>(nv_rev_share) <span class="hljs-built_in">print</span>(nv_peg_ratio) <span class="hljs-number">0.097</span> <span class="hljs-number">45.226</span> <span class="hljs-number">12.942</span> <span class="hljs-number">0.69</span>

<span class="hljs-comment">#MSI</span>

nvda1 = yf.Ticker(<span class="hljs-string">"MSI"</span>) nv_rev_growth = nvda1.info[<span class="hljs-string">'revenueGrowth'</span>] nv_debt_equity = nvda1.info[<span class="hljs-string">'debtToEquity'</span>] nv_rev_share = nvda1.info[<span class="hljs-string">'revenuePerShare'</span>] nv_peg_ratio = nvda1.info[<span class="hljs-string">'pegRatio'</span>] <span class="hljs-built_in">print</span>(nv_rev_growth) <span class="hljs-built_in">print</span>(nv_debt_equity) <span class="hljs-built_in">print</span>(nv_rev_share) <span class="hljs-built_in">print</span>(nv_peg_ratio) <span class="hljs-number">0.052</span> <span class="hljs-number">886.333</span> <span class="hljs-number">59.749</span> <span class="hljs-number">2.86</span>

<span class="hljs-comment">#NVDA</span>

nvda1 = yf.Ticker(<span class="hljs-string">"NVDA"</span>) nv_rev_growth = nvda1.info[<span class="hljs-string">'revenueGrowth'</span>] nv_debt_equity = nvda1.info[<span class="hljs-string">'debtToEquity'</span>] nv_rev_share = nvda1.info[<span class="hljs-string">'revenuePerShare'</span>] nv_peg_ratio = nvda1.info[<span class="hljs-string">'pegRatio'</span>] <span class="hljs-built_in">print</span>(nv_rev_growth) <span class="hljs-built_in">print</span>(nv_debt_equity) <span class="hljs-built_in">print</span>(nv_rev_share) <span class="hljs-built_in">print</span>(nv_peg_ratio)

<span class="hljs-number">2.653</span> <span class="hljs-number">25.725</span> <span class="hljs-number">24.675</span> <span class="hljs-number">1.03</span></pre></div><h2 id="73fa">Stock Kurtosis, Skewness & STD</h2><ul><li>Adding the S&P 500 benchmark and considering the 2Y portfolio</li></ul><div id="f560"><pre><span class="hljs-comment"># Financial data </span> <span class="hljs-keyword">import</span> quantstats <span class="hljs-keyword">as</span> qs <span class="hljs-keyword">import</span> ta <span class="hljs-keyword">import</span> yfinance <span class="hljs-keyword">as</span> yf

stocks = [<span class="hljs-string">'NVDA'</span>, <span class="hljs-string">'INTC'</span>, <span class="hljs-string">'AMD'</span>, <span class="hljs-string">'MSI'</span>,<span class="hljs-string">'^GSPC'</span>]

<span class="hljs-comment"># Fetch the data</span> <span class="hljs-keyword">import</span> yfinance <span class="hljs-keyword">as</span> yf

start=dt.today()-td(<span class="hljs-number">365</span>*<span class="hljs-number">2</span>) df = yf.download(stocks,start=start)[<span class="hljs-string">'Adj Close'</span>]

<span class="hljs-built_in">print</span>(<span class="hljs-string">'\n'</span>) <span class="hljs-built_in">print</span>(<span class="hljs-string">"NVDA kurtosis: "</span>, qs.stats.kurtosis(df.NVDA).<span class="hljs-built_in">round</span>(<span class="hljs-number">2</span>)) <span class="hljs-built_in">print</span>(<span class="hljs-string">'\n'</span>) <span class="hljs-built_in">print</span>(<span class="hljs-string">"INTC kurtosis: "</span>, qs.stats.kurtosis(df.INTC).<span class="hljs-built_in">round</span>(<span class="hljs-number">2</span>)) <span class="hljs-built_in">print</span>(<span class="hljs-string">'\n'</span>) <span class="hljs-built_in">print</span>(<span class="hljs-string">"AMD kurtosis: "</span>, qs.stats.kurtosis(df.AMD).<span class="hljs-built_in">round</span>(<span class="hljs-number">2</span>)) <span class="hljs-built_in">print</span>(<span class="hljs-string">'\n'</span>) <span class="hljs-built_in">print</span>(<span class="hljs-string">"MSI kurtosis: "</span>, qs.stats.kurtosis(df.MSI).<span class="hljs-built_in">round</span>(<span class="hljs-number">2</span>)) <span class="hljs-built_in">print</span>(<span class="hljs-string">'\n'</span>) <span class="hljs-built_in">print</span>(<span class="hljs-string">"^GSPC kurtosis: "</span>, qs.stats.kurtosis(df[<span class="hljs-string">'^GSPC'</span>]).<span class="hljs-built_in">round</span>(<span class="hljs-number">2</span>))

NVDA kurtosis: <span class="hljs-number">6.15</span>

INTC kurtosis: <span class="hljs-number">2.26</span>

AMD kurtosis: <span class="hljs-number">1.92</span>

MSI kurtosis: <span class="hljs-number">3.09</span>

^GSPC kurtosis: <span class="hljs-number">2.04</span></pre></div><div id="0d82"><pre><span class="hljs-comment"># Measuring skewness with quantstats</span> <span class="hljs-built_in">print</span>(<span class="hljs-string">'\n'</span>) <span class="hljs-built_in">print</span>(<span class="hljs-string">"NVDA skewness: "</span>, qs.stats.skew(df.NVDA).<span class="hljs-built_in">round</span>(<span class="hljs-number">2</span>)) <span class="hljs-built_in">print</span>(<span class="hljs-string">'\n'</span>) <span class="hljs-built_in">print</span>(<span class="hljs-string">"INTC skewness: "</span>, qs.stats.skew(df.INTC).<span class="hljs-built_in">round</span>(<span class="hljs-number">2</span>)) <span class="hljs-built_in">print</span>(<span class="hljs-string">'\n'</span>) <span class="hljs-built_in">print</span>(<span class="hljs-string">"AMD skewness: "</span>, qs.stats.skew(df.AMD).<span class="hljs-built_in">round</span>(<span class="hljs-number">2</span>)) <span class="hljs-built_in">print</span>(<span class="hljs-string">'\n'</span>) <span class="hljs-built_in">print</span>(<span class="hljs-string">"MSI skewness: "</span>, qs.stats.skew(df.MSI).<span class="hljs-built_in">round</span>(<span class="hljs-number">2</span>)) <span class="hljs-built_in">print</span>(<span class="hljs-string">'\n'</span>) <span class="hljs-built_in">print</span>(<span class="hljs-string">"^GSPC skewness: "</span>, qs.stats.skew(df[<span class="hljs-string">'^GSPC'</span>]).<span class="hljs-built_in">round</span>(<span class="hljs-number">2</span>))

NVDA skewness: <span class="hljs-number">1.0</span>

INTC skewness: -<span class="hljs-number">0.06</span>

AMD skewness: <span class="hljs-number">0.28</span>

MSI skewness: <span class="hljs-number">0.45</span>

^GSPC skewness: -<span class="hljs-number">0.11</span></pre></div><div id="ad53"><pre><span class="hljs-comment"># Calculating Standard Deviations</span> <span class="hljs-built_in">print</span>(<span class="hljs-string">'\n'</span>) <span class="hljs-built_in">print</span>(<span class="hljs-string">"NVDA std: "</span>, (df.NVDA.std())) <span class="hljs-built_in">print</span>(<span class="hljs-string">'\n'</span>) <span class="hljs-built_in">print</span>(<span class="hljs-string">"INTC std: "</span>, (df.INTC.std())) <span class="hljs-built_in">print</span>(<span class="hljs-string">'\n'</span>) <span class="hljs-built_in">print</span>(<span class="hljs-string">"AMD std: "</span>, (df.AMD.std())) <span class="hljs-built_in">print</span>(<span class="hljs-string">'\n'</span>) <span class="hljs-built_in">print</span>(<span class="hljs-string">"MSI std: "</span>, (df.MSI.std())) <span class="hljs-built_in">print</span>(<span class="hljs-string">'\n'</span>) <span class="hljs-built_in">print</span>(<span class="hljs-string">"^GSPC std: "</span>, (df[<span class="hljs-string">'^GSPC'</span>].std()))

NVDA std: <span class="hljs-number">214.74791733336204</span>

INTC std: <span class="hljs-number">6.555661385679709</span>

AMD std: <span class="hljs-number">34.45680060452505</span>

MSI std: <span class="hljs-number">39.28116730667171</span>

^GSPC std: <span class="hljs-number">404.1021748731829</span></pre></div><p id="f626"><b>Stock Correlation Analysis</b></p><ul><li>Displaying the seaborn pairplot of the aforementioned DataFrame df</li></ul><div id="dfe6"><pre><span class="hljs-keyword">import</span> seaborn <span class="hljs-keyword">as</span> sns sns.pairplot(df, kind = <span class="hljs-string">'reg'</span>) plt.show()</pre></div><figure id="8412"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*CmJ5eCs0Ml4JE-rXlQ3k1g.png"><figcaption>Stock pairplot vs benchmark</figcaption></figure><ul><li>Plotting the stock correlation matrix</li></ul><div id="f1b6"><pre><span class="hljs-comment"># Correlation Matrix</span> corr = df.corr() mask = np.zeros_like(corr) mask[np.triu_indices_from(mask)] = <span class="hljs-literal">True</span> sns.heatmap(corr, annot=<span class="hljs-literal">True</span>, mask = mask) plt.show()</pre></div><figure id="9223"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*AjNoxsSBGF7Zb7tGAGqCoA.png"><figcaption>Stock correlation matrix</figcaption></figure><h2 id="133d">Key Technical Indicators</h2><ul><li>Adding <a href="https://www.kaggle.com/code/lusfernandotorres/data-science-for-financial-markets">Technical Indicators (TI)</a> to gain more insights into the supply and demand of our securities.</li><li>NVDA candlesticks with key TI</li></ul><div id="48cf"><pre>start=<span class="hljs-string">'2023-01-01'</span> <span class="hljs-comment"># Downloading Stocks</span> nvda = yf.download(<span class="hljs-string">'NVDA'</span>, start = start)

<span class="hljs-comment"># Adding Moving Averages</span> nvda[<span class="hljs-string">'EMA9'</span>] = nvda[<span class="hljs-string">'Adj Close'</span>].ewm(span = <span class="hljs-number">9</span>, adjust = <span class="hljs-literal">False</span>).mean() <span class="hljs-comment"># Exponential 9-Period Moving Average</span> nvda[<span class="hljs-string">'SMA20'</span>] = nvda[<span class="hljs-string">'Adj Close'</span>].rolling(window=<span class="hljs-number">20</span>).mean() <span class="hljs-comment"># Simple 20-Period Moving Average</span> nvda[<span class="hljs-string">'SMA50'</span>] = nvda[<span class="hljs-string">'Adj Close'</span>].rolling(window=<span class="hljs-number">50</span>).mean() <span class="hljs-comment"># Simple 50-Period Moving Average</span> nvda[<span class="hljs-string">'SMA100'</span>] = nvda[<span class="hljs-string">'Adj Close'</span>].rolling(window=<span class="hljs-number">100</span>).mean() <span class="hljs-comment"># Simple 100-Period Moving Average</span> nvda[<span class="hljs-string">'SMA200'</span>] = nvda[<span class="hljs-string">'Adj Close'</span>].rolling(window=<span class="hljs-number">200</span>).mean() <span class="hljs-comment"># Simple 200-Period Moving Average</span>

<span class="hljs-comment"># Adding RSI for 14-periods </span> delta = nvda[<span class="hljs-string">'Adj Close'</span>].diff() <span class="hljs-comment"># Calculating delta</span> gain = delta.where(delta > <span class="hljs-number">0</span>,<span class="hljs-number">0</span>) <span class="hljs-comment"># Obtaining gain values</span> loss = -delta.where(delta < <span class="hljs-number">0</span>,<span class="hljs-number">0</span>) <span class="hljs-comment"># Obtaining loss values</span> avg_gain = gain.rolling(window=<span class="hljs-number">14</span>).mean() <span class="hljs-comment"># Measuring the 14-period average gain value</span> avg_loss = loss.rolling(window=<span class="hljs-number">14</span>).mean() <span class="hljs-comment"># Measuring the 14-period average loss value</span> rs = avg_gain/avg_loss <span class="hljs-comment"># Calculating the RS</span> nvda[<span class="hljs-string">'RSI'</span>] = <span class="hljs-number">100</span> - (<span class="hljs-number">100</span> / (<span class="hljs-number">1</span> + rs)) <span class="hljs-comment"># Creating an RSI column to the Data Frame </span>

<span class="hljs-comment"># Adding Bollinger Bands 20-periods</span> nvda[<span class="hljs-string">'BB_UPPER'</span>] = nvda[<span class="hljs-string">'SMA20'</span>] + <span class="hljs-number">2</span>*nvda[<span class="hljs-string">'Adj Close'</span>].rolling(window=<span class="hljs-number">20</span>).std() <span class="hljs-comment"># Upper Band</span> nvda[<span class="hljs-string">'BB_LOWER'</span>] = nvda[<span class="hljs-string">'SMA20'</span>] - <span class="hljs-number">2</span>*nvda[<span class="hljs-string">'Adj Close'</span>].rolling(window=<span class="hljs-number">20</span>).std() <span class="hljs-comment"># Lower Band</span>

<span class="hljs-comment"># Adding ATR 14-periods</span> nvda[<span class="hljs-string">'TR'</span>] = pd.DataFrame(np.maximum(np.maximum(nvda[<span class="hljs-string">'High'</span>] - nvda[<span class="hljs-string">'Low'</span>], <span class="hljs-built_in">abs</span>(nvda[<span class="hljs-string">'High'</span>] - nvda[<span class="hljs-string">'Adj Close'</span>].shift())), <span class="hljs-built_in">abs</span>(nvda[<span class="hljs-string">'Low'</span>] - nvda[<span class="hljs-string">'Adj Close'</span>].shift())), index = nvda.index) nvda[<span class="hljs-string">'ATR'</span>] = nvda[<span class="hljs-string">'TR'</span>].rolling(window = <span class="hljs-number">14</span>).mean() <span class="hljs-comment"># Creating an ART column to the Data Frame </span>

<span class="hljs-comment"># Plotting Candlestick charts with indicators</span> fig = make_subplots(rows=<span class="hljs-number">4</span>, cols=<span class="hljs-number">1</span>, shared_xaxes=<span class="hljs-literal">True</span>, vertical_spacing=<span class="hljs-number">0.05</span>,row_heights=[<span class="hljs-number">0.6</span>, <span class="hljs-number">0.10</span>, <span class="hljs-number">0.10</span>, <span class="hljs-number">0.20</span>])

<span class="hljs-comment"># Candlestick </span> fig.add_trace(go.Candlestick(x=nvda.index, <span class="hljs-built_in">open</span>=nvda[<span class="hljs-string">'Open'</span>], high=nvda[<span class="hljs-string">'High'</span>], low=nvda[<span class="hljs-string">'Low'</span>], close=nvda[<span class="hljs-string">'Adj Close'</span>], name=<span class="hljs-string">'NVDA'</span>), row=<span class="hljs-number">1</span>, col=<span class="hljs-number">1</span>)

<span class="hljs-comment"># Moving Averages</span> fig.add_trace(go.Scatter(x=nvda.index, y=nvda[<span class="hljs-string">'EMA9'</span>], mode=<span class="hljs-string">'lines'</span>, line=<span class="hljs-built_in">dict</span>(color=<span class="hljs-string">'#90EE90'</span>), name=<span class="hljs-string">'EMA9'</span>), row=<span class="hljs-number">1</span>, col=<span class="hljs-number">1</span>)

fig.add_trace(go.Scatter(x=nvda.index, y=nvda[<span class="hljs-string">'SMA20'</span>], mode=<span class="hljs-string">'lines'</span>, line=<span class="hljs-built_in">dict</span>(color=<span class="hljs-string">'yellow'</span>), name=<span class="hljs-string">'SMA20'</span>), row=<span class="hljs-number">1</span>, col=<span class="hljs-number">1</span>)

fig.add_trace(go.Scatter(x=nvda.index, y=nvda[<span class="hljs-string">'SMA50'</span>], mode=<span class="hljs-string">'lines'</span>, line=<span class="hljs-built_in">dict</span>(color=<span class="hljs-string">'orange'</span>), name=<span class="hljs-string">'SMA50'</span>), row=<span class="hljs-number">1</span>, col=<span class="hljs-number">1</span>)

fig.add_trace(go.Scatter(x=nvda.index, y=nvda[<span class="hljs-string">'SMA100'</span>], mode=<span class="hljs-string">'lines'</span>, line=<span class="hljs-built_in">dict</span>(color=<span class="hljs-string">'purple'</span>), name=<span class="hljs-string">'SMA100'</span>), row=<span class="hljs-number">1</span>, col=<span class="hljs-number">1</span>)

fig.add_trace(go.Scatter(x=nvda.index, y=nvda[<span class="hljs-string">'SMA200'</span>], mode=<span class="hljs-string">'lines'</span>, line=<span class="hljs-built_in">dict</span>(color=<span class="hljs-string">'red'</span>), name=<span class="hljs-string">'SMA200'</span>), row=<span class="hljs-number">1</span>, col=<span class="hljs-number">1</span>)

<span class="hljs-comment"># Bollinger Bands</span> fig.add_trace(go.Scatter(x=nvda.index, y=nvda[<span class="hljs-string">'BB_UPPER'</span>], mode=<span class="hljs-string">'lines'</span>, line=<span class="hljs-built_in">dict</span>(color=<span class="hljs-string">'#00BFFF'</span>), name=<span class="hljs-string">'Upper Band'</span>), row=<span class="hljs-number">1</span>, col=<span class="hljs-number">1</span>)

fig.add_trace(go.Scatter(x=nvda.index, y=nvda[<span class="hljs-string">'BB_LOWER'</span>], mode=<span class="hljs-string">'lines'</span>, line=<span class="hljs-built_in">dict</span>(color=<span class="hljs-string">'#00BFFF'</span>), name=<span class="hljs-string">'Lower Band'</span>), row=<span class="hljs-number">1</span>, col=<span class="hljs-number">1</span>)

fig.add_annotation(text=<span class="hljs-string">'NVDA'</span>, font=<span class="hljs-built_in">dict</span>(color=<span class="hljs-string">'white'</span>, size=<span class="hljs-number">40</span>), xref=<span class="hljs-string">'paper'</span>, yref=<span class="hljs-string">'paper'</span>, x=<span class="hljs-number">0.5</span>, y=<span class="hljs-number">0.65</span>, showarrow=<span class="hljs-literal">False</span>, opacity=<span class="hljs-number">0.2</span>)

<span class="hljs-comment"># Relative Strengh Index (RSI)</span> fig.add_trace(go.Scatter(x=nvda.index, y=nvda[<span class="hljs-string">'RSI'</span>], mode=<span class="hljs-string">'lines'</span>, line=<span class="hljs-built_in">dict</span>(color=<span class="hljs-string">'#CBC3E3'</span>), name=<span class="hljs-string">'RSI'</span>), row=<span class="hljs-number">2</span>, col=<span class="hljs-number">1</span>)

<span class="hljs-comment"># Adding marking lines at 70 and 30 levels</span> fig.add_shape(<span class="hljs-built_in">type</span>=<span class="hljs-string">"line"</span>, x0=nvda.index[<span class="hljs-number">0</span>], y0=<span class="hljs-number">70</span>, x1=nvda.index[-<span class="hljs-number">1</span>], y1=<span class="hljs-number">70</span>, line=<span class="hljs-built_in">dict</span>(color=<span class="hljs-string">"red"</span>, width=<span class="hljs-number">2</span>, dash=<span class="hljs-string">"dot"</span>), row=<span class="hljs-number">2</span>, col=<span class="hljs-number">1</span>) fig.add_shape(<span class="hljs-built_in">type</span>=<span class="hljs-string">"line"</span>, x0=nvda.index[<span class="hljs-number">0</span>], y0=<span class="hljs-number">30</span>, x1=nvda.index[-<span class="hljs-number">1</span>], y1=<span class="hljs-number">30</span>, line=<span class="hljs-built_in">dict</span>(color=<span class="hljs-string">"#90EE90"</span>, width=<span class="hljs-number">2</span>, dash=<span class="hljs-string">"dot"</span>), row=<span class="hljs-number">2</span>, col=<span class="hljs-number">1</span>)

<span class="hljs-comment"># Average True Range (ATR)</span> fig.add_trace(go.Scatter(x=nvda.index, y=nvda[<span class="hljs-string">'ATR'</span>], mode=<span class="hljs-string">'lines'</span>, line=<span class="hljs-built_in">dict</span>(color=<span class="hljs-string">'#00BFFF'</span>), name=<span class="hljs-string">'ATR'</span>), row=<span class="hljs-number">3</span>, col=<span class="hljs-number">1</span>)

<span class="hljs-comment"># Volume</span> fig.add_trace(go.Bar(x=nvda.index, y=nvda[<span class="hljs-string">'Volume'</span>], name=<span class="hljs-string">'Volume'</span>, marker=<span class="hljs-built_in">dict</span>(color=<span class="hljs-string">'orange'</span>, opacity=<span class="hljs-number">1.0</span>)), row=<span class="hljs-number">4</span>, col=<span class="hljs-number">1</span>)

<span class="hljs-comment"># Layout</span> fig.update_layout(title=<span class="hljs-string">'NVDA Candlestick Chart'</span>, yaxis=<span class="hljs-built_in">dict</span>(title=<span class="hljs-string">'Price (USD)'</span>), height=<span class="hljs-number">1000</span>, template = <span class="hljs-string">'plotly_dark'</span>)

<span class="hljs-comment"># Axes and subplots</span> fig.update_xaxes(rangeslider_visible=<span class="hljs-literal">False</span>, row=<span class="hljs-number">1</span>, col=<span class="hljs-number">1</span>) fig.update_xaxes(rangeslider_visible=<span class="hljs-literal">False</span>, row=<span class="hljs-number">4</span>, col=<span class="hljs-number">1</span>) fig.update_yaxes(title_text=<span class="hljs-string">'Price (USD)'</span>, row=<span class="hljs-number">1</span>, col=<span class="hljs-number">1</span>) fig.update_yaxes(title_text=<span class="hljs-string">'RSI'</span>, row=<span class="hljs-number">2</span>, col=<span class="hljs-number">1</span>) fig.update_yaxes(title_text=<span class="hljs-string">'ATR'</span>, row=<span class="hljs-number">3</span>, col=<span class="hljs-number">1</span>) fig.update_yaxes(title_text=<span class="hljs-string">'Volume'</span>, row=<span class="hljs-number">4</span>, col=<span class="hljs-number">1</span>)

fig.show()</pre></div><figure id="60fb"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*1dG0Wv-HwHcF3Q4KuXqhbA.png"><figcaption>NVDA candlesticks with key TI</figcaption></figure><ul><li>AMD candlesticks with key TI</li></ul><div id="f16f"><pre>start=<span class="hljs-string">'2023-01-01'</span> <span class="hljs-comment"># Downloading Stocks</span> nvda = yf.download(<span class="hljs-string">'AMD'</span>, start = start) <span class="hljs-comment"># Adding Moving Averages</span> nvda[<span class="hljs-string">'EMA9'</span>] = nvda[<span class="hljs-string">'Adj Close'</span>].ewm(span = <span class="hljs-number">9</span>, adjust = <span class="hljs-literal">False</span>).mean() <span class="hljs-comment"># Exponential 9-Period Moving Average</span> nvda[<span class="hljs-string">'SMA20'</span>] = nvda[<span class="hljs-string">'Adj Close'</span>].rolling(window=<span class="hljs-number">20</span>).mean() <span class="hljs-comment"># Simple 20-Period Moving Average</span> nvda[<span class="hljs-string">'SMA50'</span>] = nvda[<span class="hljs-string">'Adj Close'</span>].rolling(window=<span class="hljs-number">50</span>).mean() <span class="hljs-comment"># Simple 50-Period Moving Average</span> nvda[<span class="hljs-string">'SMA100'</span>] = nvda[<span class="hljs-string">'Adj Close'</span>].rolling(window=<span class="hljs-number">100</span>).mean() <span class="hljs-comment"># Simple 100-Period Moving Average</span> nvda[<span class="hljs-string">'SMA200'</span>] = nvda[<span class="hljs-string">'Adj Close'</span>].rolling(window=<span class="hljs-number">200</span>).mean() <span class="hljs-comment"># Simple 200-Period Moving Average</span>

<span class="hljs-comment"># Adding RSI for 14-periods </span> delta = nvda[<span class="hljs-string">'Adj Close'</span>].diff() <span class="hljs-comment"># Calculating delta</span> gain = delta.where(delta > <span class="hljs-number">0</span>,<span class="hljs-number">0</span>) <span class="hljs-comment"># Obtaining gain values</span> loss = -delta.where(delta < <span class="hljs-number">0</span>,<span class="hljs-number">0</span>) <span class="hljs-comment"># Obtaining loss values</span> avg_gain = gain.rolling(window=<span class="hljs-number">14</span>).mean() <span class="hljs-comment"># Measuring the 14-period average gain value</span> avg_loss = loss.rolling(window=<span class="hljs-number">14</span>).mean() <span class="hljs-comment"># Measuring the 14-period average loss value</span> rs = avg_gain/avg_loss <span class="hljs-comment"># Calculating the RS</span> nvda[<span class="hljs-string">'RSI'</span>] = <span class="hljs-number">100</span> - (<span class="hljs-number">100</span> / (<span class="hljs-number">1</span> + rs)) <span class="hljs-comment"># Creating an RSI column to the Data Frame </span>

<span class="hljs-comment"># Adding Bollinger Bands 20-periods</span> nvda[<span class="hljs-string">'BB_UPPER'</span>] = nvda[<span class="hljs-string">'SMA20'</span>] + <span class="hljs-number">2</span>*nvda[<span class="hljs-string">'Adj Close'</span>].rolling(window=<span class="hljs-number">20</span>).std() <span class="hljs-comment"># Upper Band</span> nvda[<span class="hljs-string">'BB_LOWER'</span>] = nvda[<span class="hljs-string">'SMA20'</span>] - <span class="hljs-number">2</span>*nvda[<span class="hljs-string">'Adj Close'</span>].rolling(window=<span class="hljs-number">20</span>).std() <span class="hljs-comment"># Lower Band</span>

<span class="hljs-comment"># Adding ATR 14-periods</span> nvda[<span class="hljs-string">'TR'</span>] = pd.DataFrame(np.maximum(np.maximum(nvda[<span class="hljs-string">'High'</span>] - nvda[<span class="hljs-string">'Low'</span>], <span class="hljs-built_in">abs</span>(nvda[<span class="hljs-string">'High'</span>] - nvda[<span class="hljs-string">'Adj Close'</span>].shift())), <span class="hljs-built_in">abs</span>(nvda[<span class="hljs-string">'Low'</span>] - nvda[<span class="hljs-string">'Adj Close'</span>].shift())), index = nvda.index) nvda[<span class="hljs-string">'ATR'</span>] = nvda[<span class="hljs-string">'TR'</span>].rolling(window = <span class="hljs-number">14</span>).mean() <span class="hljs-comment"># Creating an ART column to the Data Frame </span>

<span class="hljs-comment"># Plotting Candlestick charts with indicators</span> fig = make_subplots(rows=<span class="hljs-number">4</span>, cols=<span class="hljs-number">1</span>, shared_xaxes=<span class="hljs-literal">True</span>, vertical_spacing=<span class="hljs-number">0.05</span>,row_heights=[<span class="hljs-number">0.6</span>, <span class="hljs-number">0.10</span>, <span class="hljs-number">0.10</span>, <span class="hljs-number">0.20</span>])

<span class="hljs-comment"># Candlestick </span> fig.add_trace(go.Candlestick(x=nvda.index, <span class="hljs-built_in">open</span>=nvda[<span class="hljs-string">'Open'</span>], high=nvda[<span class="hljs-string">'High'</span>], low=nvda[<span class="hljs-string">'Low'</span>], close=nvda[<span class="hljs-string">'Adj Close'</span>], name=<span class="hljs-string">'AMD'</span>), row=<span class="hljs-number">1</span>, col=<span class="hljs-number">1</span>)

<span class="hljs-comment"># Moving Averages</span> fig.add_trace(go.Scatter(x=nvda.index, y=nvda[<span class="hljs-string">'EMA9'</span>], mode=<span class="hljs-string">'lines'</span>, line=<span class="hljs-built_in">dict</span>(color=<span class="hljs-string">'#90EE90'</span>), name=<span class="hljs-string">'EMA9'</span>), row=<span class="hljs-number">1</span>, col=<span class="hljs-number">1</span>)

fig.add_trace(go.Scatter(x=nvda.index, y=nvda[<span class="hljs-string">'SMA20'</span>], mode=<span class="hljs-string">'lines'</span>, line=<span class="hljs-built_in">dict</span>(color=<span class="hljs-string">'yellow'</span>), name=<span class="hljs-string">'SMA20'</span>), row=<span class="hljs-number">1</span>, col=<span class="hljs-number">1</span>)

fig.add_trace(go.Scatter(x=nvda.index, y=nvda[<span class="hljs-string">'SMA50'</span>], mode=<span class="hljs-string">'lines'</span>, line=<span class="hljs-built_in">dict</span>(color=<span class="hljs-string">'orange'</span>), name=<span class="hljs-string">'SMA50'</span>), row=<span class="hljs-number">1</span>, col=<span class="hljs-number">1</span>)

fig.add_trace(go.Scatter(x=nvda.index, y=nvda[<span class="hljs-string">'SMA100'</span>], mode=<span class="hljs-string">'lines'</span>, line=<span class="hljs-built_in">dict</span>(color=<span class="hljs-string">'purple'</span>), name=<span class="hljs-string">'SMA100'</span>), row=<span class="hljs-number">1</span>, col=<span class="hljs-number">1</span>)

fig.add_trace(go.Scatter(x=nvda.index, y=nvda[<span class="hljs-string">'SMA200'</span>], mode=<span class="hljs-string">'lines'</span>, line=<span class="hljs-built_in">dict</span>(color=<span class="hljs-string">'red'</span>), name=<span class="hljs-string">'SMA200'</span>), row=<span class="hljs-number">1</span>, col=<span class="hljs-number">1</span>)

<span class="hljs-comment"># Bollinger Bands</span> fig.add_trace(go.Scatter(x=nvda.index, y=nvda[<span class="hljs-string">'BB_UPPER'</span>], mode=<span class="hljs-string">'lines'</span>, line=<span class="hljs-built_in">dict</span>(color=<span class="hljs-string">'#00BFFF'</span>), name=<span class="hljs-string">'Upper Band'</span>), row=<span class="hljs-number">1</span>, col=<span class="hljs-number">1</span>)

fig.add_trace(go.Scatter(x=nvda.index, y=nvda[<span class="hljs-string">'BB_LOWER'</span>], mode=<span class="hljs-string">'lines'</span>, line=<span class="hljs-built_in">dict</span>(color=<span class="hljs-string">'#00BFFF'</span>), name=<span class="hljs-string">'Lower Band'</span>), row=<span class="hljs-number">1</span>, col=<span class="hljs-number">1</span>)

fig.add_annotation(text=<span class="hljs-string">'AMD'</span>, font=<span class="hljs-built_in">dict</span>(color=<span class="hljs-string">'white'</span>, size=<span class="hljs-number">40</span>), xref=<span class="hljs-string">'paper'</span>, yref=<span class="hljs-string">'paper'</span>, x=<span class="hljs-number">0.5</span>, y=<span class="hljs-number">0.65</span>, showarrow=<span class="hljs-literal">False</span>, opacity=<span class="hljs-number">0.2</span>)

<span class="hljs-comment"># Relative Strengh Index (RSI)</span> fig.add_trace(go.Scatter(x=nvda.index, y=nvda[<span class="hljs-string">'RSI'</span>], mode=<span class="hljs-string">'lines'</span>, line=<span class="hljs-built_in">dict</span>(color=<span class="hljs-string">'#CBC3E3'</span>), name=<span class="hljs-string">'RSI'</span>), row=<span class="hljs-number">2</span>, col=<span class="hljs-number">1</span>)

<span class="hljs-comment"># Adding marking lines at 70 and 30 levels</span> fig.add_shape(<span class="hljs-built_in">type</span>=<span class="hljs-string">"line"</span>, x0=nvda.index[<span class="hljs-number">0</span>], y0=<span class="hljs-number">70</span>, x1=nvda.index[-<span class="hljs-number">1</span>], y1=<span class="hljs-number">70</span>, line=<span class="hljs-built_in">dict</span>(color=<span class="hljs-string">"red"</span>, width=<span class="hljs-number">2</span>, dash=<span class="hljs-string">"dot"</span>), row=<span class="hljs-number">2</span>, col=<span class="hljs-number">1</span>) fig.add_shape(<span class="hljs-built_in">type</span>=<span class="hljs-string">"line"</span>, x0=nvda.index[<span class="hljs-number">0</span>], y0=<span class="hljs-number">30</span>, x1=nvda.index[-<span class="hljs-number">1</span>], y1=<span class="hljs-number">30</span>, line=<span class="hljs-built_in">dict</span>(color=<span class="hljs-string">"#90EE90"</span>, width=<span class="hljs-number">2</span>, dash=<span class="hljs-string">"dot"</span>), row=<span class="hljs-number">2</span>, col=<span class="hljs-number">1</span>)

<span class="hljs-comment"># Average True Range (ATR)</span> fig.add_trace(go.Scatter(x=nvda.index, y=nvda[<span class="hljs-string">'ATR'</span>], mode=<span class="hljs-string">'lines'</span>, line=<span class="hljs-built_in">dict</span>(color=<span class="hljs-string">'#00BFFF'</span>), name=<span class="hljs-string">'ATR'</span>), row=<span class="hljs-number">3</span>, col=<span class="hljs-number">1</span>)

<span class="hljs-comment"># Volume</span> fig.add_trace(go.Bar(x=nvda.index, y=nvda[<span class="hljs-string">'Volume'</span>], name=<span class="hljs-string">'Volume'</span>, marker=<span class="hljs-built_in">dict</span>(color=<span class="hljs-string">'orange'</span>, opacity=<span class="hljs-number">1.0</span>)), row=<span class="hljs-number">4</span>, col=<span class="hljs-number">1</span>)

<span class="hljs-comment"># Layout</span> fig.update_layout(title=<span class="hljs-string">'AMD Candlestick Chart'</span>, yaxis=<span class="hljs-built_in">dict</span>(title=<span class="hljs-string">'Price (USD)'</span>), height=<span class="hljs-number">1000</span>, template = <span class="hljs-string">'plotly_dark'</span>)

<span class="hljs-comment"># Axes and subplots</span> fig.update_xaxes(rangeslider_visible=<span class="hljs-literal">False</span>, row=<span class="hljs-number">1</span>, col=<span class="hljs-number">1</span>) fig.update_xaxes(rangeslider_visible=<span class="hljs-literal">False</span>, row=<span class="hljs-number">4</span>, col=<span class="hljs-number">1</span>) fig.update_yaxes(title_text=<span class="hljs-string">'Price (USD)'</span>, row=<span class="hljs-number">1</span>, col=<span class="hljs-number">1</span>) fig.update_yaxes(title_text=<span class="hljs-string">'RSI'</span>, row=<span class="hljs-number">2</span>, col=<span class="hljs-number">1</span>) fig.update_yaxes(title_text=<span class="hljs-string">'ATR'</span>, row=<span class="hljs-number">3</span>, col=<span class="hljs-number">1</span>) fig.update_yaxes(title_text=<span class="hljs-string">'Volume'</span>, row=<span class="hljs-number">4</span>, col=<span class="hljs-number">1</span>)

fig.show()</pre></div><figure id="64a4"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*QHQnbABgQr6O_nUx7FKP3w.png"><figcaption>AMD candlesticks with key TI</figcaption></figure><ul><li>MSI candlesticks with key TI</li></ul><div id="7821"><pre>start=<span class="hljs-string">'2023-01-01'</span> <span class="hljs-comment"># Downloading Stocks</span> nvda = yf.download(<span class="hljs-string">'MSI'</span>, start = start) <span class="hljs-comment"># Adding Moving Averages</span> nvda[<span class="hljs-string">'EMA9'</span>] = nvda[<span class="hljs-string">'Adj Close'</span>].ewm(span = <span class="hljs-number">9</span>, adjust = <span class="hljs-literal">False</span>).mean() <span class="hljs-comment"># Exponential 9-Period Moving Average</span> nvda[<span class="hljs-string">'SMA20'</span>] = nvda[<span class="hljs-string">'Adj Close'</span>].rolling(window=<span class="hljs-number">20</span>).mean() <span class="hljs-comment"># Simple 20-Period Moving Average</span> nvda[<span class="hljs-string">'SMA50'</span>] = nvda[<span class="hljs-string">'Adj Close'</span>].rolling(window=<span class="hljs-number">50</span>).mean() <span class="hljs-comment"># Simple 50-Period Moving Average</span> nvda[<span class="hljs-string">'SMA100'</span>] = nvda[<span class="hljs-string">'Adj Close'</span>].rolling(window=<span class="hljs-number">100</span>).mean() <span class="hljs-comment"># Simple 100-Period Moving Average</span> nvda[<span class="hljs-string">'SMA200'</span>] = nvda[<span class="hljs-string">'Adj Close'</span>].rolling(window=<span class="hljs-number">200</span>).mean() <span class="hljs-comment"># Simple 200-Period Moving Average</span>

<span class="hljs-comment"># Adding RSI for 14-periods </span> delta = nvda[<span class="hljs-string">'Adj Close'</span>].diff() <span class="hljs-comment"># Calculating delta</span> gain = delta.where(delta > <span class="hljs-number">0</span>,<span class="hljs-number">0</span>) <span class="hljs-comment"># Obtaining gain values</span> loss = -delta.where(delta < <span class="hljs-number">0</span>,<span class="hljs-number">0</span>) <span class="hljs-comment"># Obtaining loss values</span> avg_gain = gain.rolling(window=<span class="hljs-number">14</span>).mean() <span class="hljs-comment"># Measuring the 14-period average gain value</span> avg_loss = loss.rolling(window=<span class="hljs-number">14</span>).mean() <span class="hljs-comment"># Measuring the 14-period average loss value</span> rs = avg_gain/avg_loss <span class="hljs-comment"># Calculating the RS</span> nvda[<span class="hljs-string">'RSI'</span>] = <span class="hljs-number">100</span> - (<span class="hljs-number">100</span> / (<span class="hljs-number">1</span> + rs)) <span class="hljs-comment"># Creating an RSI column to the Data Frame </span>

<span class="hljs-comment"># Adding Bollinger Bands 20-periods</span> nvda[<span class="hljs-string">'BB_UPPER'</span>] = nvda[<span class="hljs-string">'SMA20'</span>] + <span class="hljs-number">2</span>*nvda[<span class="hljs-string">'Adj Close'</span>].rolling(window=<span class="hljs-number">20</span>).std() <span class="hljs-comment"># Upper Band</span> nvda[<span class="hljs-string">'BB_LOWER'</span>] = nvda[<span class="hljs-string">'SMA20'</span>] - <span class="hljs-number">2</span>*nvda[<span class="hljs-string">'Adj Close'</span>].rolling(window=<span class="hljs-number">20</span>).std() <span class="hljs-comment"># Lower Band</span>

<span class="hljs-comment"># Adding ATR 14-periods</span> nvda[<span class="hljs-string">'TR'</span>] = pd.DataFrame(np.maximum(np.maximum(nvda[<span class="hljs-string">'High'</span>] - nvda[<span class="hljs-string">'Low'</span>], <span class="hljs-built_in">abs</span>(nvda[<span class="hljs-string">'High'</span>] - nvda[<span class="hljs-string">'Adj Close'</span>].shift())), <span class="hljs-built_in">abs</span>(nvda[<span class="hljs-string">'Low'</span>] - nvda[<span class="hljs-string">'Adj Close'</span>].shift())), index = nvda.index) nvda[<span class="hljs-string">'ATR'</span>] = nvda[<span class="hljs-string">'TR'</span>].rolling(window = <span class="hljs-number">14</span>).mean() <span class="hljs-comment"># Creating an ART column to the Data Frame </span>

<span class="hljs-comment"># Plotting Candlestick charts with indicators</span> fig = make_subplots(rows=<span class="hljs-number">4</span>, cols=<span class="hljs-number">1</span>, shared_xaxes=<span class="hljs-literal">True</span>, vertical_spacing=<span class="hljs-number">0.05</span>,row_heights=[<span class="hljs-number">0.6</span>, <span class="hljs-number">0.10</span>, <span class="hljs-number">0.10</span>, <span class="hljs-number">0.20</span>])

<span class="hljs-comment"># Candlestick </span> fig.add_trace(go.Candlestick(x=nvda.index, <span class="hljs-built_in">open</span>=nvda[<span class="hljs-string">'Open'</span>], high=nvda[<span class="hljs-string">'High'</span>], low=nvda[<span class="hljs-string">'Low'</span>], close=nvda[<span class="hljs-string">'Adj Close'</span>], name=<span class="hljs-string">'MSI'</span>), row=<span class="hljs-number">1</span>, col=<span class="hljs-number">1</span>)

<span class="hljs-comment"># Moving Averages</span> fig.add_trace(go.Scatter(x=nvda.index, y=nvda[<span class="hljs-string">'EMA9'</span>], mode=<span class="hljs-string">'lines'</span>, line=<span class="hljs-built_in">dict</span>(color=<span class="hljs-string">'#90EE90'</span>), name=<span class="hljs-string">'EMA9'</span>), row=<span class="hljs-number">1</span>, col=<span class="hljs-number">1</span>)

fig.add_trace(go.Scatter(x=nvda.index, y=nvda[<span class="hljs-string">'SMA20'</span>], mode=<span class="hljs-string">'lines'</span>, line=<span class="hljs-built_in">dict</span>(color=<span class="hljs-string">'yellow'</span>), name=<span class="hljs-string">'SMA20'</span>), row=<span class="hljs-number">1</span>, col=<span class="hljs-number">1</span>)

fig.add_trace(go.Scatter(x=nvda.index, y=nvda[<span class="hljs-string">'SMA50'</span>], mode=<span class="hljs-string">'lines'</span>, line=<span class="hljs-built_in">dict</span>(color=<span class="hljs-string">'orange'</span>), name=<span class="hljs-string">'SMA50'</span>), row=<span class="hljs-number">1</span>, col=<span class="hljs-number">1</span>)

fig.add_trace(go.Scatter(x=nvda.index, y=nvda[<span class="hljs-string">'SMA100'</span>], mode=<span class="hljs-string">'lines'</span>, line=<span class="hljs-built_in">dict</span>(color=<span class="hljs-string">'purple'</span>), name=<span class="hljs-string">'SMA100'</span>), row=<span class="hljs-number">1</span>, col=<span class="hljs-number">1</span>)

fig.add_trace(go.Scatter(x=nvda.index, y=nvda[<span class="hljs-string">'SMA200'</span>], mode=<span class="hljs-string">'lines'</span>, line=<span class="hljs-built_in">dict</span>(color=<span class="hljs-string">'red'</span>), name=<span class="hljs-string">'SMA200'</span>), row=<span class="hljs-number">1</span>, col=<span class="hljs-number">1</span>)

<span class="hljs-comment"># Bollinger Bands</span> fig.add_trace(go.Scatter(x=nvda.index, y=nvda[<span class="hljs-string">'BB_UPPER'</span>], mode=<span class="hljs-string">'lines'</span>, line=<span class="hljs-built_in">dict</span>(color=<span class="hljs-string">'#00BFFF'</span>), name=<span class="hljs-string">'Upper Band'</span>), row=<span class="hljs-number">1</span>, col=<span class="hljs-number">1</span>)

fig.add_trace(go.Scatter(x=nvda.index, y=nvda[<span class="hljs-string">'BB_LOWER'</span>], mode=<span class="hljs-string">'lines'</span>, line=<span class="hljs-built_in">dict</span>(color=<span class="hljs-string">'#00BFFF'</span>), name=<span class="hljs-string">'Lower Band'</span>), row=<span class="hljs-number">1</span>, col=<span class="hljs-number">1</span>)

fig.add_annotation(text=<span class="hljs-string">'MSI'</span>, font=<span class="hljs-built_in">dict</span>(color=<span class="hljs-string">'white'</span>, size=<span class="hljs-number">40</span>), xref=<span class="hljs-string">'paper'</span>, yref=<span class="hljs-string">'paper'</span>, x=<span class="hljs-number">0.5</span>, y=<span class="hljs-number">0.65</span>, showarrow=<span class="hljs-literal">False</span>, opacity=<span class="hljs-number">0.2</span>)

<span class="hljs-comment"># Relative Strengh Index (RSI)</span> fig.add_trace(go.Scatter(x=nvda.index, y=nvda[<span class="hljs-string">'RSI'</span>], mode=<span class="hljs-string">'lines'</span>, line=<span class="hljs-built_in">dict</span>(color=<span class="hljs-string">'#CBC3E3'</span>), name=<span class="hljs-string">'RSI'</span>), row=<span class="hljs-number">2</span>, col=<span class="hljs-number">1</span>)

<span class="hljs-comment"># Adding marking lines at 70 and 30 levels</span> fig.add_shape(<span class="hljs-built_in">type</span>=<span class="hljs-string">"line"</span>, x0=nvda.index[<span class="hljs-number">0</span>], y0=<span class="hljs-number">70</span>, x1=nvda.index[-<span class="hljs-number">1</span>], y1=<span class="hljs-number">70</span>, line=<span class="hljs-built_in">dict</span>(color=<span class="hljs-string">"red"</span>, width=<span class="hljs-number">2</span>, dash=<span class="hljs-string">"dot"</span>), row=<span class="hljs-number">2</span>, col=<span class="hljs-number">1</span>) fig.add_shape(<span class="hljs-built_in">type</span>=<span class="hljs-string">"line"</span>, x0=nvda.index[<span class="hljs-number">0</span>], y0=<span class="hljs-number">30</span>, x1=nvda.index[-<span class="hljs-number">1</span>], y1=<span class="hljs-number">30</span>, line=<span class="hljs-built_in">dict</span>(color=<span class="hljs-string">"#90EE90"</span>, width=<span class="hljs-number">2</span>, dash=<span class="hljs-string">"dot"</span>), row=<span class="hljs-number">2</span>, col=<span class="hljs-number">1</span>)

<span class="hljs-comment"># Average True Range (ATR)</span> fig.add_trace(go.Scatter(x=nvda.index, y=nvda[<span class="hljs-string">'ATR'</span>], mode=<span class="hljs-string">'lines'</span>, line=<span class="hljs-built_in">dict</span>(color=<span class="hljs-string">'#00BFFF'</span>), name=<span class="hljs-string">'ATR'</span>), row=<span class="hljs-number">3</span>, col=<span class="hljs-number">1</span>)

<span class="hljs-comment"># Volume</span> fig.add_trace(go.Bar(x=nvda.index, y=nvda[<span class="hljs-string">'Volume'</span>], name=<span class="hljs-string">'Volume'</span>, marker=<span class="hljs-built_in">dict</span>(color=<span class="hljs-string">'orange'</span>, opacity=<span class="hljs-number">1.0</span>)), row=<span class="hljs-number">4</span>, col=<span class="hljs-number">1</span>)

<span class="hljs-comment"># Layout</span> fig.update_layout(title=<span class="hljs-string">'MSI Candlestick Chart'</span>, yaxis=<span class="hljs-built_in">dict</span>(title=<span class="hljs-string">'Price (USD)'</span>), height=<span class="hljs-number">1000</span>, template = <span class="hljs-string">'plotly_dark'</span>)

<span class="hljs-comment"># Axes and subplots</span> fig.update_xaxes(rangeslider_visible=<span class="hljs-literal">False</span>, row=<span class="hljs-number">1</span>, col=<span class="hljs-number">1</span>) fig.update_xaxes(rangeslider_visible=<span class="hljs-literal">False</span>, row=<span class="hljs-number">4</span>, col=<span class="hljs-number">1</span>) fig.update_yaxes(title_text=<span class="hljs-string">'Price (USD)'</span>, row=<span class="hljs-number">1</span>, col=<span class="hljs-number">1</span>) fig.update_yaxes(title_text=<span class="hljs-string">'RSI'</span>, row=<span class="hljs-number">2</span>, col=<span class="hljs-number">1</span>) fig.update_yaxes(title_text=<span class="hljs-string">'ATR'</span>, row=<span class="hljs-number">3</span>, col=<span class="hljs-number">1</span>) fig.update_yaxes(title_text=<span class="hljs-string">'Volume'</span>, row=<span class="hljs-number">4</span>, col=<span class="hljs-number">1</span>)</pre></div><figure id="fe91"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*CVPlwzO_-0283krk1v6Iqw.png"><figcaption>MSI candlesticks with key TI</figcaption></figure><ul><li>INTC candlesticks with key TI</li></ul><div id="32c1"><pre>start=<span class="hljs-string">'2023-01-01'</span> <span class="hljs-comment"># Downloading Stocks</span> nvda = yf.download(<span class="hljs-string">'INTC'</span>, start = start) <span class="hljs-comment"># Adding Moving Averages</span> nvda[<span class="hljs-string">'EMA9'</span>] = nvda[<span class="hljs-string">'Adj Close'</span>].ewm(span = <span class="hljs-number">9</span>, adjust = <span class="hljs-literal">False</span>).mean() <span class="hljs-comment"># Exponential 9-Period Moving Average</span> nvda[<span class="hljs-string">'SMA20'</span>] = nvda[<span class="hljs-string">'Adj Close'</span>].rolling(window=<span class="hljs-number">20</span>).mean() <span class="hljs-comment"># Simple 20-Period Moving Average</span> nvda[<span class="hljs-string">'SMA50'</span>] = nvda[<span class="hljs-string">'Adj Close'</span>].rolling(window=<span class="hljs-number">50</span>).mean() <span class="hljs-comment"># Simple 50-Period Moving Average</span> nvda[<span class="hljs-string">'SMA100'</span>] = nvda[<span class="hljs-string">'Adj Close'</span>].rolling(window=<span class="hljs-number">100</span>).mean() <span class="hljs-comment"># Simple 100-Period Moving Average</span> nvda[<span class="hljs-string">'SMA200'</span>] = nvda[<span class="hljs-string">'Adj Close'</span>].rolling(window=<span class="hljs-number">200</span>).mean() <span class="hljs-comment"># Simple 200-Period Moving Average</span>

<span class="hljs-comment"># Adding RSI for 14-periods </span> delta = nvda[<span class="hljs-string">'Adj Close'</span>].diff() <span class="hljs-comment"># Calculating delta</span> gain = delta.where(delta > <span class="hljs-number">0</span>,<span class="hljs-number">0</span>) <span class="hljs-comment"># Obtaining gain values</span> loss = -delta.where(delta < <span class="hljs-number">0</span>,<span class="hljs-number">0</span>) <span class="hljs-comment"># Obtaining loss values</span> avg_gain = gain.rolling(window=<span class="hljs-number">14</span>).mean() <span class="hljs-comment"># Measuring the 14-period average gain value</span> avg_loss = loss.rolling(window=<span class="hljs-number">14</span>).mean() <span class="hljs-comment"># Measuring the 14-period average loss value</span> rs = avg_gain/avg_loss <span class="hljs-comment"># Calculating the RS</span> nvda[<span class="hljs-string">'RSI'</span>] = <span class="hljs-number">100</span> - (<span class="hljs-number">100</span> / (<span class="hljs-number">1</span> + rs)) <span class="hljs-comment"># Creating an RSI column to the Data Frame </span>

<span class="hljs-comment"># Adding Bollinger Bands 20-periods</span> nvda[<span class="hljs-string">'BB_UPPER'</span>] = nvda[<span class="hljs-string">'SMA20'</span>] + <span class="hljs-number">2</span>*nvda[<span class="hljs-string">'Adj Close'</span>].rolling(window=<span class="hljs-number">20</span>).std() <span class="hljs-comment"># Upper Band</span> nvda[<span class="hljs-string">'BB_LOWER'</span>] = nvda[<span class="hljs-string">'SMA20'</span>] - <span class="hljs-number">2</span>*nvda[<span class="hljs-string">'Adj Close'</span>].rolling(window=<span class="hljs-number">20</span>).std() <span class="hljs-comment"># Lower Band</span>

<span class="hljs-comment"># Adding ATR 14-periods</span> nvda[<span class="hljs-string">'TR'</span>] = pd.DataFrame(np.maximum(np.maximum(nvda[<span class="hljs-string">'High'</span>] - nvda[<span class="hljs-string">'Low'</span>], <span class="hljs-built_in">abs</span>(nvda[<span class="hljs-string">'High'</span>] - nvda[<span class="hljs-string">'Adj Close'</span>].shift())), <span class="hljs-built_in">abs</span>(nvda[<span class="hljs-string">'Low'</span>] - nvda[<span class="hljs-string">'Adj Close'</span>].shift())), index = nvda.index) nvda[<span class="hljs-string">'ATR'</span>] = nvda[<span class="hljs-string">'TR'</span>].rolling(window = <span class="hljs-number">14</span>).mean() <span class="hljs-comment"># Creating an ART column to the Data Frame </span>

<span class="hljs-comment"># Plotting Candlestick charts with indicators</span> fig = make_subplots(rows=<span class="hljs-number">4</span>, cols=<span class="hljs-number">1</span>, shared_xaxes=<span class="hljs-literal">True</span>, vertical_spacing=<span class="hljs-number">0.05</span>,row_heights=[<span class="hljs-number">0.6</span>, <span class="hljs-number">0.10</span>, <span class="hljs-number">0.10</span>, <span class="hljs-number">0.20</span>])

<span class="hljs-comment"># Candlestick </span> fig.add_trace(go.Candlestick(x=nvda.index, <span class="hljs-built_in">open</span>=nvda[<span class="hljs-string">'Open'</span>], high=nvda[<span class="hljs-string">'High'</span>], low=nvda[<span class="hljs-string">'Low'</span>], close=nvda[<span class="hljs-string">'Adj Close'</span>], name=<span class="hljs-string">'INTC'</span>), row=<span class="hljs-number">1</span>, col=<span class="hljs-number">1</span>)

<span class="hljs-comment"># Moving Averages</span> fig.add_trace(go.Scatter(x=nvda.index, y=nvda[<span class="hljs-string">'EMA9'</span>], mode=<span class="hljs-string">'lines'</span>, line=<span class="hljs-built_in">dict</span>(color=<span class="hljs-string">'#90EE90'</span>), name=<span class="hljs-string">'EMA9'</span>), row=<span class="hljs-number">1</span>, col=<span class="hljs-number">1</span>)

fig.add_trace(go.Scatter(x=nvda.index, y=nvda[<span class="hljs-string">'SMA20'</span>], mode=<span class="hljs-string">'lines'</span>, line=<span class="hljs-built_in">dict</span>(color=<span class="hljs-string">'yellow'</span>), name=<span class="hljs-string">'SMA20'</span>), row=<span class="hljs-number">1</span>, col=<span class="hljs-number">1</span>)

fig.add_trace(go.Scatter(x=nvda.index, y=nvda[<span class="hljs-string">'SMA50'</span>], mode=<span class="hljs-string">'lines'</span>, line=<span class="hljs-built_in">dict</span>(color=<span class="hljs-string">'orange'</span>), name=<span class="hljs-string">'SMA50'</span>), row=<span class="hljs-number">1</span>, col=<span class="hljs-number">1</span>)

fig.add_trace(go.Scatter(x=nvda.index, y=nvda[<span class="hljs-string">'SMA100'</span>], mode=<span class="hljs-string">'lines'</span>, line=<span class="hljs-built_in">dict</span>(color=<span class="hljs-string">'purple'</span>), name=<span class="hljs-string">'SMA100'</span>), row=<span class="hljs-number">1</span>, col=<span class="hljs-number">1</span>)

fig.add_trace(go.Scatter(x=nvda.index, y=nvda[<span class="hljs-string">'SMA200'</span>], mode=<span class="hljs-string">'lines'</span>, line=<span class="hljs-built_in">dict</span>(color=<span class="hljs-string">'red'</span>), name=<span class="hljs-string">'SMA200'</span>), row=<span class="hljs-number">1</span>, col=<span class="hljs-number">1</span>)

<span class="hljs-comment"># Bollinger Bands</span> fig.add_trace(go.Scatter(x=nvda.index, y=nvda[<span class="hljs-string">'BB_UPPER'</span>], mode=<span class="hljs-string">'lines'</span>, line=<span class="hljs-built_in">dict</span>(color=<span class="hljs-string">'#00BFFF'</span>), name=<span class="hljs-string">'Upper Band'</span>), row=<span class="hljs-number">1</span>, col=<span class="hljs-number">1</span>)

fig.add_trace(go.Scatter(x=nvda.index, y=nvda[<span class="hljs-string">'BB_LOWER'</span>], mode=<span class="hljs-string">'lines'</span>, line=<span class="hljs-built_in">dict</span>(color=<span class="hljs-string">'#00BFFF'</span>), name=<span class="hljs-string">'Lower Band'</span>), row=<span class="hljs-number">1</span>, col=<span class="hljs-number">1</span>)

fig.add_annotation(text=<span class="hljs-string">'INTC'</span>, font=<span class="hljs-built_in">dict</span>(color=<span class="hljs-string">'white'</span>, size=<span class="hljs-number">40</span>), xref=<span class="hljs-string">'paper'</span>, yref=<span class="hljs-string">'paper'</span>, x=<span class="hljs-number">0.5</span>, y=<span class="hljs-number">0.65</span>, showarrow=<span class="hljs-literal">False</span>, opacity=<span class="hljs-number">0.2</span>)

<span class="hljs-comment"># Relative Strengh Index (RSI)</span> fig.add_trace(go.Scatter(x=nvda.index, y=nvda[<span class="hljs-string">'RSI'</span>], mode=<span class="hljs-string">'lines'</span>, line=<span class="hljs-built_in">dict</span>(color=<span class="hljs-string">'#CBC3E3'</span>), name=<span class="hljs-string">'RSI'</span>), row=<span class="hljs-number">2</span>, col=<span class="hljs-number">1</span>)

<span class="hljs-comment"># Adding marking lines at 70 and 30 levels</span> fig.add_shape(<span class="hljs-built_in">type</span>=<span class="hljs-string">"line"</span>, x0=nvda.index[<span class="hljs-number">0</span>], y0=<span class="hljs-number">70</span>, x1=nvda.index[-<span class="hljs-number">1</span>], y1=<span class="hljs-number">70</span>, line=<span class="hljs-built_in">dict</span>(color=<span class="hljs-string">"red"</span>, width=<span class="hljs-number">2</span>, dash=<span class="hljs-string">"dot"</span>), row=<span class="hljs-number">2</span>, col=<span class="hljs-number">1</span>) fig.add_shape(<span class="hljs-built_in">type</span>=<span class="hljs-string">"line"</span>, x0=nvda.index[<span class="hljs-number">0</span>], y0=<span class="hljs-number">30</span>, x1=nvda.index[-<span class="hljs-number">1</span>], y1=<span class="hljs-number">30</span>, line=<span class="hljs-built_in">dict</span>(color=<span class="hljs-string">"#90EE90"</span>, width=<span class="hljs-number">2</span>, dash=<span class="hljs-string">"dot"</span>), row=<span class="hljs-number">2</span>, col=<span class="hljs-number">1</span>)

<span class="hljs-comment"># Average True Range (ATR)</span> fig.add_trace(go.Scatter(x=nvda.index, y=nvda[<span class="hljs-string">'ATR'</span>], mode=<span class="hljs-string">'lines'</span>, line=<span class="hljs-built_in">dict</span>(color=<span class="hljs-string">'#00BFFF'</span>), name=<span class="hljs-string">'ATR'</span>), row=<span class="hljs-number">3</span>, col=<span class="hljs-number">1</span>)

<span class="hljs-comment"># Volume</span> fig.add_trace(go.Bar(x=nvda.index, y=nvda[<span class="hljs-string">'Volume'</span>], name=<span class="hljs-string">'Volume'</span>, marker=<span class="hljs-built_in">dict</span>(color=<span class="hljs-string">'orange'</span>, opacity=<span class="hljs-number">1.0</span>)), row=<span class="hljs-number">4</span>, col=<span class="hljs-number">1</span>)

<span class="hljs-comment"># Layout</span> fig.update_layout(title=<span class="hljs-string">'INTC Candlestick Chart'</span>, yaxis=<span class="hljs-built_in">dict</span>(title=<span class="hljs-string">'Price (USD)'</span>), height=<span class="hljs-number">1000</span>, template = <span class="hljs-string">'plotly_dark'</span>)

<span class="hljs-comment"># Axes and subplots</span> fig.update_xaxes(rangeslider_visible=<span class="hljs-literal">False</span>, row=<span class="hljs-number">1</span>, col=<span class="hljs-number">1</span>) fig.update_xaxes(rangeslider_visible=<span class="hljs-literal">False</span>, row=<span class="hljs-number">4</span>, col=<span class="hljs-number">1</span>) fig.update_yaxes(title_text=<span class="hljs-string">'Price (USD)'</span>, row=<span class="hljs-number">1</span>, col=<span class="hljs-number">1</span>) fig.update_yaxes(title_text=<span class="hljs-string">'RSI'</span>, row=<span class="hljs-number">2</span>, col=<span class="hljs-number">1</span>) fig.update_yaxes(title_text=<span class="hljs-string">'ATR'</span>, row=<span class="hljs-number">3</span>, col=<span class="hljs-number">1</span>) fig.update_yaxes(title_text=<span class="hljs-string">'Volume'</span>, row=<span class="hljs-number">4</span>, col=<span class="hljs-number">1</span>)

</pre></div><figure id="c971"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*pOnWyb3PsVzqUnAsgnn3Hg.png"><figcaption>INTC candlesticks with key TI</figcaption></figure><h2 id="fda0">Backtesting INTC Trading Strategies</h2><ul><li>The above INTC candlesticks with key TI suggest that we need to outperform the passive buy-and-hold strategy of this stock. In doing so, we will implement and backtest the following <a href="https://blog.devgenius.io/algorithmic-trading-backtesting-a-strategy-in-python-3a136be16ece">TI-based trading strategies</a></li></ul><div id="3c92"><pre><span class="hljs-comment"># Importing necessary libraries</span> <span class="hljs-keyword">import</span> pandas <span class="hljs-keyword">as</span> pd <span class="hljs-keyword">import</span> numpy <span class="hljs-keyword">as</span> np <span class="hljs-keyword">import</span> matplotlib.pyplot <span class="hljs-keyword">as</span> plt <span class="hljs-keyword">import</span> yfinance <span class="hljs-keyword">as</span> yf <span class="hljs-keyword">import</span> pyfolio <span class="hljs-keyword">as</span> pf <span class="hljs-keyword">import</span> datetime <span class="hljs-keyword">as</span> dt

<span class="hljs-keyword">import</span> os <span class="hljs-keyword">import</span> warnings

<span class="hljs-comment"># print all outputs</span> <span class="hljs-keyword">from</span> IPython.core.interactiveshell <span class="hljs-keyword">import</span> InteractiveShell InteractiveShell.ast_node_interactivity = <span class="hljs-string">"all"</span>

<span class="hljs-comment"># downloading historical necessary data for backtesting and analysis</span> _start = dt.date(<span class="hljs-number">2022</span>,<span class="hljs-number">1</span>,<span class="hljs-number">2</span>) _end = dt.date(<span class="hljs-number">2024</span>,<span class="hljs-number">4</span>,<span class="hljs-number">20</span>) ti

Options

cker = <span class="hljs-string">'INTC'</span> df = yf.download(ticker, start = _start, end = _end) <span class="hljs-comment">#df.tail()</span>

<span class="hljs-comment"># calculating buy and hold strategy returns</span> df[<span class="hljs-string">'bnh_returns'</span>] = np.log(df[<span class="hljs-string">'Adj Close'</span>]/df[<span class="hljs-string">'Adj Close'</span>].shift(<span class="hljs-number">1</span>))

<span class="hljs-comment"># creating bollinger band indicators</span> df[<span class="hljs-string">'ma20'</span>] = df[<span class="hljs-string">'Adj Close'</span>].rolling(window=<span class="hljs-number">20</span>).mean() df[<span class="hljs-string">'std'</span>] = df[<span class="hljs-string">'Adj Close'</span>].rolling(window=<span class="hljs-number">20</span>).std() df[<span class="hljs-string">'upper_band'</span>] = df[<span class="hljs-string">'ma20'</span>] + (<span class="hljs-number">2</span> * df[<span class="hljs-string">'std'</span>]) df[<span class="hljs-string">'lower_band'</span>] = df[<span class="hljs-string">'ma20'</span>] - (<span class="hljs-number">2</span> * df[<span class="hljs-string">'std'</span>]) df.drop([<span class="hljs-string">'Open'</span>,<span class="hljs-string">'High'</span>,<span class="hljs-string">'Low'</span>],axis=<span class="hljs-number">1</span>,inplace=<span class="hljs-literal">True</span>,errors=<span class="hljs-string">'ignore'</span>) <span class="hljs-comment">#df.tail(5)</span>

<span class="hljs-comment"># BUY condition</span> df[<span class="hljs-string">'signal'</span>] = np.where((df[<span class="hljs-string">'Adj Close'</span>] < df[<span class="hljs-string">'lower_band'</span>]) & (df[<span class="hljs-string">'Adj Close'</span>].shift(<span class="hljs-number">1</span>) >= df[<span class="hljs-string">'lower_band'</span>]),<span class="hljs-number">1</span>,<span class="hljs-number">0</span>)

<span class="hljs-comment"># SELL condition</span> df[<span class="hljs-string">'signal'</span>] = np.where( (df[<span class="hljs-string">'Adj Close'</span>] > df[<span class="hljs-string">'upper_band'</span>]) & (df[<span class="hljs-string">'Adj Close'</span>].shift(<span class="hljs-number">1</span>) <= df[<span class="hljs-string">'upper_band'</span>]),-<span class="hljs-number">1</span>,df[<span class="hljs-string">'signal'</span>]) <span class="hljs-comment"># creating long and short positions </span> df[<span class="hljs-string">'position'</span>] = df[<span class="hljs-string">'signal'</span>].replace(to_replace=<span class="hljs-number">0</span>, method=<span class="hljs-string">'ffill'</span>)

<span class="hljs-comment"># shifting by 1, to account of close price return calculations</span> df[<span class="hljs-string">'position'</span>] = df[<span class="hljs-string">'position'</span>].shift(<span class="hljs-number">1</span>)

<span class="hljs-comment"># calculating stretegy returns</span> df[<span class="hljs-string">'strategy_returns'</span>] = df[<span class="hljs-string">'bnh_returns'</span>] * (df[<span class="hljs-string">'position'</span>])

<span class="hljs-comment">#df.tail(5)</span>

<span class="hljs-comment"># comparing buy & hold strategy / bollinger bands strategy returns</span> <span class="hljs-built_in">print</span>(<span class="hljs-string">"Buy and hold returns:"</span>,df[<span class="hljs-string">'bnh_returns'</span>].cumsum()[-<span class="hljs-number">1</span>]) <span class="hljs-built_in">print</span>(<span class="hljs-string">"Strategy returns:"</span>,df[<span class="hljs-string">'strategy_returns'</span>].cumsum()[-<span class="hljs-number">1</span>])

<span class="hljs-comment"># plotting strategy historical performance over time</span> df[[<span class="hljs-string">'bnh_returns'</span>,<span class="hljs-string">'strategy_returns'</span>]] = df[[<span class="hljs-string">'bnh_returns'</span>,<span class="hljs-string">'strategy_returns'</span>]].cumsum() df[[<span class="hljs-string">'bnh_returns'</span>,<span class="hljs-string">'strategy_returns'</span>]].plot(grid=<span class="hljs-literal">True</span>, figsize=(<span class="hljs-number">12</span>, <span class="hljs-number">8</span>))

Buy <span class="hljs-keyword">and</span> hold returns: -<span class="hljs-number">0.3770989996574775</span> Strategy returns: <span class="hljs-number">1.3603005119382139</span></pre></div><figure id="767d"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*FCSpUz_Jz9OU4g3rEdbp0A.png"><figcaption>INTC buy-and-hold vs TI strategy returns</figcaption></figure><ul><li>Printing pyfolio strategy QC diagnostics</li></ul><div id="24ee"><pre><span class="hljs-keyword">import</span> pyfolio <span class="hljs-keyword">as</span> pf pf.create_simple_tear_sheet(df[<span class="hljs-string">'strategy_returns'</span>].diff())

Start date <span class="hljs-number">2022</span>-01-03 End date <span class="hljs-number">2024</span>-04-<span class="hljs-number">19</span> Total months <span class="hljs-number">27</span> Backtest Annual <span class="hljs-keyword">return</span> <span class="hljs-number">68.595</span>% Cumulative returns <span class="hljs-number">230.676</span>% Annual volatility <span class="hljs-number">38.018</span>% Sharpe ratio <span class="hljs-number">1.57</span> Calmar ratio <span class="hljs-number">2.68</span> Stability <span class="hljs-number">0.92</span> Max drawdown -<span class="hljs-number">25.626</span>% Omega ratio <span class="hljs-number">1.31</span> Sortino ratio <span class="hljs-number">2.56</span> Skew NaN Kurtosis NaN Tail ratio <span class="hljs-number">1.26</span> Daily value at risk -<span class="hljs-number">4.553</span>%</pre></div><figure id="792d"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*tEaMYPOJeZxomGU2aSx75A.png"><figcaption></figcaption></figure><figure id="ae71"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*rkA_g8NnhckW2YsqxDJfkg.png"><figcaption>INTC backtesting cumulative returns</figcaption></figure><ul><li>Plotting INTC backtesting trading signals, BB, MA20 and Close price</li></ul><div id="35c3"><pre>df.tail() Close Adj Close Volume bnh_returns ma20 std upper_band lower_band signal position strategy_returns Date
<span class="hljs-number">2024</span>-04-<span class="hljs-number">15</span> <span class="hljs-number">36.310001</span> <span class="hljs-number">36.310001</span> <span class="hljs-number">50751600</span> -<span class="hljs-number">0.317231</span> <span class="hljs-number">40.7040</span> <span class="hljs-number">2.792515</span> <span class="hljs-number">46.289030</span> <span class="hljs-number">35.118970</span> <span class="hljs-number">0</span> <span class="hljs-number">1.0</span> <span class="hljs-number">1.420168</span> <span class="hljs-number">2024</span>-04-<span class="hljs-number">16</span> <span class="hljs-number">36.259998</span> <span class="hljs-number">36.259998</span> <span class="hljs-number">30607500</span> -<span class="hljs-number">0.318610</span> <span class="hljs-number">40.3815</span> <span class="hljs-number">2.918270</span> <span class="hljs-number">46.218039</span> <span class="hljs-number">34.544961</span> <span class="hljs-number">0</span> <span class="hljs-number">1.0</span> <span class="hljs-number">1.418790</span> <span class="hljs-number">2024</span>-04-<span class="hljs-number">17</span> <span class="hljs-number">35.680000</span> <span class="hljs-number">35.680000</span> <span class="hljs-number">41173300</span> -<span class="hljs-number">0.334734</span> <span class="hljs-number">40.0630</span> <span class="hljs-number">3.070239</span> <span class="hljs-number">46.203479</span> <span class="hljs-number">33.922522</span> <span class="hljs-number">0</span> <span class="hljs-number">1.0</span> <span class="hljs-number">1.402665</span> <span class="hljs-number">2024</span>-04-<span class="hljs-number">18</span> <span class="hljs-number">35.040001</span> <span class="hljs-number">35.040001</span> <span class="hljs-number">42334400</span> -<span class="hljs-number">0.352834</span> <span class="hljs-number">39.7050</span> <span class="hljs-number">3.221649</span> <span class="hljs-number">46.148299</span> <span class="hljs-number">33.261701</span> <span class="hljs-number">0</span> <span class="hljs-number">1.0</span> <span class="hljs-number">1.384565</span> <span class="hljs-number">2024</span>-04-<span class="hljs-number">19</span> <span class="hljs-number">34.200001</span> <span class="hljs-number">34.200001</span> <span class="hljs-number">58968800</span> -<span class="hljs-number">0.377099</span> <span class="hljs-number">39.2940</span> <span class="hljs-number">3.377611</span> <span class="hljs-number">46.049222</span> <span class="hljs-number">32.538778</span> <span class="hljs-number">0</span> <span class="hljs-number">1.0</span> <span class="hljs-number">1.360301</span>

buy_price = [] sell_price = [] prices=df[<span class="hljs-string">'Close'</span>] <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-built_in">len</span>(prices)): <span class="hljs-keyword">if</span> df[<span class="hljs-string">'signal'</span>][i] > <span class="hljs-number">0.0</span>: buy_price.append(prices[i]) sell_price.append(np.nan) <span class="hljs-keyword">if</span> df[<span class="hljs-string">'signal'</span>][i] < <span class="hljs-number">0.0</span>: sell_price.append(prices[i]) buy_price.append(np.nan) <span class="hljs-keyword">if</span> df[<span class="hljs-string">"signal"</span>][i] == <span class="hljs-number">0.0</span>: sell_price.append(np.nan) buy_price.append(np.nan)

plt.figure(figsize=(<span class="hljs-number">12</span>,<span class="hljs-number">7</span>)) plt.plot(df[<span class="hljs-string">"Close"</span>], color=<span class="hljs-string">"black"</span>, label=<span class="hljs-string">"Price"</span>) plt.plot(df.index, buy_price, marker = <span class="hljs-string">'^'</span>, markersize = <span class="hljs-number">8</span>, color = <span class="hljs-string">'green'</span>, linewidth = <span class="hljs-number">0</span>, label = <span class="hljs-string">'BUY SIGNAL'</span>) plt.plot(df.index, sell_price, marker = <span class="hljs-string">'v'</span>, markersize = <span class="hljs-number">8</span>, color = <span class="hljs-string">'r'</span>, linewidth = <span class="hljs-number">0</span>, label = <span class="hljs-string">'SELL SIGNAL'</span>) plt.plot(df[<span class="hljs-string">"upper_band"</span>], color=<span class="hljs-string">"blue"</span>, label=<span class="hljs-string">"Upper BB"</span>) plt.plot(df[<span class="hljs-string">"lower_band"</span>], color=<span class="hljs-string">"green"</span>, label=<span class="hljs-string">"Lower BB"</span>) plt.plot(df[<span class="hljs-string">"ma20"</span>], color=<span class="hljs-string">"orange"</span>, label=<span class="hljs-string">"MA20"</span>) plt.legend() plt.grid() plt.title(<span class="hljs-string">"Backtesting INTC TI Trading Strategy"</span>,fontsize=<span class="hljs-number">16</span>) plt.xlabel(<span class="hljs-string">"Date"</span>,fontsize=<span class="hljs-number">16</span>) plt.ylabel(<span class="hljs-string">"Close Price USD"</span>,fontsize=<span class="hljs-number">16</span>) plt.show()</pre></div><figure id="40d4"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*F3ojRUokfOkErQrlXMRw8g.png"><figcaption>Backtesting INTC TI Trading Strategy</figcaption></figure><ul><li>Comparing these results to the ^GSPC cumulative returns</li></ul><div id="494c"><pre><span class="hljs-comment"># downloading historical necessary data for backtesting and analysis</span> _start = dt.date(<span class="hljs-number">2022</span>,<span class="hljs-number">1</span>,<span class="hljs-number">2</span>) _end = dt.date(<span class="hljs-number">2024</span>,<span class="hljs-number">4</span>,<span class="hljs-number">20</span>) ticker = <span class="hljs-string">'^GSPC'</span> dfg = yf.download(ticker, start = _start, end = _end) <span class="hljs-comment"># calculating buy and hold strategy returns</span> dfg[<span class="hljs-string">'bnh_returns'</span>] = np.log(dfg[<span class="hljs-string">'Adj Close'</span>]/dfg[<span class="hljs-string">'Adj Close'</span>].shift(<span class="hljs-number">1</span>)) <span class="hljs-comment">#dfg.tail(3)</span> <span class="hljs-built_in">print</span>(<span class="hljs-string">"^GSPC Buy and Hold returns:"</span>,dfg[<span class="hljs-string">'bnh_returns'</span>].cumsum()[-<span class="hljs-number">1</span>])

dfg[<span class="hljs-string">'daily_return'</span>] = dfg[<span class="hljs-string">'Close'</span>].pct_change() <span class="hljs-comment"># calculate cumluative return</span> dfg[<span class="hljs-string">'cum_return'</span>] = np.exp(np.log1p(dfg[<span class="hljs-string">'daily_return'</span>]).cumsum()) <span class="hljs-built_in">print</span> (dfg[<span class="hljs-string">'cum_return'</span>]) dfg[<span class="hljs-string">'cum_return'</span>].plot()

^GSPC Buy <span class="hljs-keyword">and</span> Hold returns: <span class="hljs-number">0.03496333020354546</span></pre></div><figure id="13ca"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*d97_bh-x3pmRBNudeSHk2A.png"><figcaption>^GSPC cumulative returns</figcaption></figure><h2 id="d914">SciPy Portfolio Optimization</h2><ul><li>Let’s consider several popular stochastic simulation <a href="https://www.machinelearningplus.com/machine-learning/portfolio-optimization-python-example/">techniques</a> of creating an optimized portfolio<i> </i>of our 4 tech assets<i>,</i> for which our investment strategy has the maximum return and minimum risk or max(ROI/Risk) as compared to the S&P 500 benchmark.</li><li>For example, <a href="https://www.kaggle.com/code/lusfernandotorres/data-science-for-financial-markets">the Markowitz Mean-Variance Optimization Model</a> is a widely-used framework for constructing portfolios with the best risk-return relationship.</li><li>Firstly, we estimate expected returns using daily prices as input.</li><li>Secondly, we invoke the covariance matrix as the most commonly used risk model.</li><li>Read more about the implemented scipy optimization <a href="https://github.com/PyroQuant/Portfolio-Optimizer/blob/main/portfolio_optimizer.ipynb">algorithm</a> and the related PO <a href="https://www.kaggle.com/code/lusfernandotorres/data-science-for-financial-markets">guide</a> for data scientists.</li></ul><div id="6126"><pre><span class="hljs-comment">#Importing Libraries</span> <span class="hljs-keyword">import</span> numpy <span class="hljs-keyword">as</span> np <span class="hljs-keyword">import</span> pandas <span class="hljs-keyword">as</span> pd <span class="hljs-keyword">import</span> yfinance <span class="hljs-keyword">as</span> yf <span class="hljs-keyword">import</span> matplotlib.pyplot <span class="hljs-keyword">as</span> plt <span class="hljs-keyword">from</span> scipy.optimize <span class="hljs-keyword">import</span> minimize <span class="hljs-keyword">from</span> scipy.stats <span class="hljs-keyword">import</span> norm <span class="hljs-keyword">from</span> scipy.stats <span class="hljs-keyword">import</span> skew, kurtosis <span class="hljs-keyword">from</span> scipy.stats.mstats <span class="hljs-keyword">import</span> gmean <span class="hljs-comment"># Select Optimization Criteria 'sharpe', 'cvar', 'sortino' or 'variance'</span> optimization_criterion = <span class="hljs-string">'cvar'</span>

<span class="hljs-comment">#Read input Adj Close prices</span> symbols = [<span class="hljs-string">'NVDA'</span>, <span class="hljs-string">'AMD'</span>, <span class="hljs-string">'MSI'</span>, <span class="hljs-string">'INTC'</span>] start_date = <span class="hljs-string">'2022-01-01'</span> end_date = <span class="hljs-string">'2024-04-20'</span>

data = yf.download(symbols, start=start_date, end=end_date)[<span class="hljs-string">'Adj Close'</span>] data.tail() Ticker AMD INTC MSI NVDA Date
<span class="hljs-number">2024</span>-04-<span class="hljs-number">15</span> <span class="hljs-number">160.320007</span> <span class="hljs-number">36.310001</span> <span class="hljs-number">338.579987</span> <span class="hljs-number">860.010010</span> <span class="hljs-number">2024</span>-04-<span class="hljs-number">16</span> <span class="hljs-number">163.460007</span> <span class="hljs-number">36.259998</span> <span class="hljs-number">340.109985</span> <span class="hljs-number">874.150024</span> <span class="hljs-number">2024</span>-04-<span class="hljs-number">17</span> <span class="hljs-number">154.020004</span> <span class="hljs-number">35.680000</span> <span class="hljs-number">340.510010</span> <span class="hljs-number">840.349976</span> <span class="hljs-number">2024</span>-04-<span class="hljs-number">18</span> <span class="hljs-number">155.080002</span> <span class="hljs-number">35.040001</span> <span class="hljs-number">339.459991</span> <span class="hljs-number">846.710022</span> <span class="hljs-number">2024</span>-04-<span class="hljs-number">19</span> <span class="hljs-number">146.639999</span> <span class="hljs-number">34.200001</span> <span class="hljs-number">339.649994</span> <span class="hljs-number">762.000000</span>

<span class="hljs-comment">#Calculate daily returns</span> returns = data.pct_change().dropna()</pre></div><ul><li>Defining the optimization objective <a href="https://github.com/PyroQuant/Portfolio-Optimizer/blob/main/portfolio_optimizer.ipynb">functions</a> , constraints and bounds</li></ul><div id="c55d"><pre><span class="hljs-keyword">def</span> <span class="hljs-title function_">objective_sharpe</span>(<span class="hljs-params">weights</span>): <span class="hljs-keyword">return</span> -np.dot(weights, returns.mean()) / np.sqrt(np.dot(weights.T, np.dot(returns.cov() * <span class="hljs-number">252</span>, weights))) <span class="hljs-keyword">def</span> <span class="hljs-title function_">objective_cvar</span>(<span class="hljs-params">weights</span>): portfolio_returns = np.dot(returns, weights) portfolio_mean = portfolio_returns.mean() portfolio_std = portfolio_returns.std() conf_level = <span class="hljs-number">0.05</span> <span class="hljs-comment"># Confidence level</span> cvar = portfolio_mean - portfolio_std * norm.ppf(conf_level) <span class="hljs-keyword">return</span> cvar <span class="hljs-keyword">def</span> <span class="hljs-title function_">objective_sortino</span>(<span class="hljs-params">weights</span>): portfolio_returns = np.dot(returns, weights) downside_returns = portfolio_returns[portfolio_returns < <span class="hljs-number">0</span>] downside_std = downside_returns.std() sortino_ratio = portfolio_returns.mean() / downside_std <span class="hljs-keyword">return</span> -sortino_ratio
<span class="hljs-keyword">def</span> <span class="hljs-title function_">objective_variance</span>(<span class="hljs-params">weights</span>): <span class="hljs-keyword">return</span> np.dot(weights.T, np.dot(returns.cov() * <span class="hljs-number">252</span>, weights))

cons = ({<span class="hljs-string">'type'</span>: <span class="hljs-string">'eq'</span>, <span class="hljs-string">'fun'</span>: <span class="hljs-keyword">lambda</span> x: np.<span class="hljs-built_in">sum</span>(x) - <span class="hljs-number">1</span>}) bounds = <span class="hljs-built_in">tuple</span>((<span class="hljs-number">0</span>, <span class="hljs-number">1</span>) <span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-built_in">len</span>(symbols)))</pre></div><ul><li>Running the PO <a href="https://github.com/PyroQuant/Portfolio-Optimizer/blob/main/portfolio_optimizer.ipynb">algorithm</a> with optimal weights</li></ul><div id="5cbb"><pre><span class="hljs-comment"># Optimization</span> init_guess = np.array(<span class="hljs-built_in">len</span>(symbols) * [<span class="hljs-number">1.</span> / <span class="hljs-built_in">len</span>(symbols),]) <span class="hljs-keyword">if</span> optimization_criterion == <span class="hljs-string">'sharpe'</span>: opt_results = minimize(objective_sharpe, init_guess, method=<span class="hljs-string">'SLSQP'</span>, bounds=bounds, constraints=cons) <span class="hljs-keyword">elif</span> optimization_criterion == <span class="hljs-string">'cvar'</span>: opt_results = minimize(objective_cvar, init_guess, method=<span class="hljs-string">'SLSQP'</span>, bounds=bounds, constraints=cons) <span class="hljs-keyword">elif</span> optimization_criterion == <span class="hljs-string">'sortino'</span>: opt_results = minimize(objective_sortino, init_guess, method=<span class="hljs-string">'SLSQP'</span>, bounds=bounds, constraints=cons) <span class="hljs-keyword">elif</span> optimization_criterion == <span class="hljs-string">'variance'</span>: opt_results = minimize(objective_variance, init_guess, method=<span class="hljs-string">'SLSQP'</span>, bounds=bounds, constraints=cons)

<span class="hljs-comment"># Optimal weights</span> optimal_weights = opt_results.x

<span class="hljs-comment"># Optimize all criteria</span> opt_results_cvar = minimize(objective_cvar, init_guess, method=<span class="hljs-string">'SLSQP'</span>, bounds=bounds, constraints=cons) opt_results_sortino = minimize(objective_sortino, init_guess, method=<span class="hljs-string">'SLSQP'</span>, bounds=bounds, constraints=cons) opt_results_variance = minimize(objective_variance, init_guess, method=<span class="hljs-string">'SLSQP'</span>, bounds=bounds, constraints=cons) opt_results_sharpe = minimize(objective_sharpe, init_guess, method=<span class="hljs-string">'SLSQP'</span>, bounds=bounds, constraints=cons)

<span class="hljs-comment"># Optimal weights for each criterion</span> optimal_weights_cvar = opt_results_cvar.x optimal_weights_sortino = opt_results_sortino.x optimal_weights_variance = opt_results_variance.x optimal_weights_sharpe = opt_results_sharpe.x</pre></div><ul><li>Plotting the efficient frontier</li></ul><div id="0c8d"><pre>port_returns = [] port_volatility = [] sharpe_ratio = [] all_weights = [] <span class="hljs-comment"># almacena los pesos de todas las carteras simuladas</span>

num_assets = <span class="hljs-built_in">len</span>(symbols) num_portfolios = <span class="hljs-number">50000</span>

np.random.seed(<span class="hljs-number">101</span>)

<span class="hljs-keyword">for</span> single_portfolio <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(num_portfolios): weights = np.random.random(num_assets) weights /= np.<span class="hljs-built_in">sum</span>(weights) returns_portfolio = np.dot(weights, returns.mean()) * <span class="hljs-number">252</span> volatility = np.sqrt(np.dot(weights.T, np.dot(returns.cov() * <span class="hljs-number">252</span>, weights))) sr = returns_portfolio / volatility sharpe_ratio.append(sr) port_returns.append(returns_portfolio) port_volatility.append(volatility) all_weights.append(weights) <span class="hljs-comment"># registra los pesos para esta cartera</span>

plt.figure(figsize=(<span class="hljs-number">12</span>, <span class="hljs-number">8</span>)) plt.scatter(port_volatility, port_returns, c=sharpe_ratio, cmap=<span class="hljs-string">'viridis'</span>) plt.colorbar(label=<span class="hljs-string">'Sharpe Ratio'</span>) plt.xlabel(<span class="hljs-string">'Volatility'</span>,fontsize=<span class="hljs-number">14</span>) plt.ylabel(<span class="hljs-string">'Return'</span>,fontsize=<span class="hljs-number">14</span>) plt.grid()</pre></div><figure id="7d0e"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*N1tZ-SHdyI0jjxF03SaRLw.png"><figcaption>The efficient frontier plot with optimization_criterion = ‘cvar’</figcaption></figure><ul><li>Plotting the optimal portfolio for each criterion in the above domain</li></ul><div id="f4cf"><pre>plt.figure(figsize=(<span class="hljs-number">12</span>, <span class="hljs-number">8</span>)) plt.scatter(port_volatility, port_returns, c=sharpe_ratio, cmap=<span class="hljs-string">'viridis'</span>)

opt_returns_cvar = np.dot(optimal_weights_cvar, returns.mean()) * <span class="hljs-number">252</span> opt_volatility_cvar = np.sqrt(np.dot(optimal_weights_cvar.T, np.dot(returns.cov() * <span class="hljs-number">252</span>, optimal_weights_cvar))) opt_portfolio_cvar = plt.scatter(opt_volatility_cvar, opt_returns_cvar, color=<span class="hljs-string">'hotpink'</span>, s=<span class="hljs-number">250</span>, label=<span class="hljs-string">'CVaR'</span>)

opt_returns_sortino = np.dot(optimal_weights_sortino, returns.mean()) * <span class="hljs-number">252</span> opt_volatility_sortino = np.sqrt(np.dot(optimal_weights_sortino.T, np.dot(returns.cov() * <span class="hljs-number">252</span>, optimal_weights_sortino))) opt_portfolio_sortino = plt.scatter(opt_volatility_sortino, opt_returns_sortino, color=<span class="hljs-string">'g'</span>, s=<span class="hljs-number">50</span>, label=<span class="hljs-string">'Sortino'</span>)

opt_returns_variance = np.dot(optimal_weights_variance, returns.mean()) * <span class="hljs-number">252</span> opt_volatility_variance = np.sqrt(np.dot(optimal_weights_variance.T, np.dot(returns.cov() * <span class="hljs-number">252</span>, optimal_weights_variance))) opt_portfolio_variance = plt.scatter(opt_volatility_variance, opt_returns_variance, color=<span class="hljs-string">'b'</span>, s=<span class="hljs-number">50</span>, label=<span class="hljs-string">'Variance'</span>)

opt_returns_sharpe = np.dot(optimal_weights_sharpe, returns.mean()) * <span class="hljs-number">252</span> opt_volatility_sharpe = np.sqrt(np.dot(optimal_weights_sharpe.T, np.dot(returns.cov() * <span class="hljs-number">252</span>, optimal_weights_sharpe))) opt_portfolio_sharpe = plt.scatter(opt_volatility_sharpe, opt_returns_sharpe, color=<span class="hljs-string">'r'</span>, s=<span class="hljs-number">50</span>, label=<span class="hljs-string">'Sharpe'</span>)

plt.legend(loc=<span class="hljs-string">'upper left'</span>) plt.colorbar(label=<span class="hljs-string">'Sharpe Ratio'</span>) plt.xlabel(<span class="hljs-string">'Volatility'</span>,fontsize=<span class="hljs-number">14</span>) plt.ylabel(<span class="hljs-string">'Return'</span>,fontsize=<span class="hljs-number">14</span>) plt.grid() plt.show()</pre></div><figure id="763f"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*LR-ZWv2HlMpW0h5g_DiI-Q.png"><figcaption>Optimal portfolio for each criterion in the return-volatility domain</figcaption></figure><ul><li>Calculating and printing <a href="https://www.kaggle.com/code/lusfernandotorres/data-science-for-financial-markets">descriptive statistics</a> of the optimized portfolios</li></ul><div id="6e68"><pre><span class="hljs-comment"># Function to calculate the maximum drawdown</span> <span class="hljs-keyword">def</span> <span class="hljs-title function_">max_drawdown</span>(<span class="hljs-params">return_series</span>): comp_ret = (<span class="hljs-number">1</span> + return_series).cumprod() peak = comp_ret.expanding(min_periods=<span class="hljs-number">1</span>).<span class="hljs-built_in">max</span>() dd = (comp_ret/peak) - <span class="hljs-number">1</span> <span class="hljs-keyword">return</span> dd.<span class="hljs-built_in">min</span>()

<span class="hljs-comment"># Function to calculate more detailed descriptive statistics</span> <span class="hljs-keyword">def</span> <span class="hljs-title function_">detailed_portfolio_statistics</span>(<span class="hljs-params">weights</span>): portfolio_returns = returns.dot(weights)

<span class="hljs-comment"># General descriptive statistics</span>
mean_return_annualized = gmean(portfolio_returns + <span class="hljs-number">1</span>)**<span class="hljs-number">252</span> - <span class="hljs-number">1</span>
std_dev_annualized = portfolio_returns.std() * np.sqrt(<span class="hljs-number">252</span>)
skewness = skew(portfolio_returns)
kurt = kurtosis(portfolio_returns)
max_dd = max_drawdown(portfolio_returns)
count = <span class="hljs-built_in">len</span>(portfolio_returns)

<span class="hljs-comment"># Optimization metrics</span>
risk_free_rate = <span class="hljs-number">0.00</span>
sharpe_ratio = (mean_return_annualized - risk_free_rate) / std_dev_annualized
conf_level = <span class="hljs-number">0.05</span>
cvar = mean_return_annualized - std_dev_annualized * norm.ppf(conf_level)
downside_returns = portfolio_returns[portfolio_returns &lt; <span class="hljs-number">0</span>]
downside_std_dev = downside_returns.std() * np.sqrt(<span class="hljs-number">252</span>)
sortino_ratio = mean_return_annualized / downside_std_dev
variance = std_dev_annualized ** <span class="hljs-number">2</span> 

<span class="hljs-keyword">return</span> mean_return_annualized, std_dev_annualized, skewness, kurt, max_dd, count, sharpe_ratio, cvar, sortino_ratio, variance

<span class="hljs-comment"># Calculate statistics for each portfolioCalculate statistics for each portfolio</span> statistics_cvar = detailed_portfolio_statistics(optimal_weights_cvar) statistics_sortino = detailed_portfolio_statistics(optimal_weights_sortino) statistics_variance = detailed_portfolio_statistics(optimal_weights_variance) statistics_sharpe = detailed_portfolio_statistics(optimal_weights_sharpe)

<span class="hljs-comment"># Statistics names</span> statistics_names = [<span class="hljs-string">'Annualized return'</span>, <span class="hljs-string">'Annualized volatility'</span>, <span class="hljs-string">'Skewness'</span>, <span class="hljs-string">'Kurtosis'</span>, <span class="hljs-string">'Max Drawdown'</span>, <span class="hljs-string">'Data content'</span>, <span class="hljs-string">'Sharpe Ratio'</span>, <span class="hljs-string">'CVaR'</span>, <span class="hljs-string">'Sortino Ratio'</span>, <span class="hljs-string">'Variance'</span>]

<span class="hljs-comment"># Dictionary that associates the names of optimization methods with optimal weights and statistics</span> portfolio_data = { <span class="hljs-string">'CVaR'</span>: { <span class="hljs-string">'weights'</span>: optimal_weights_cvar, <span class="hljs-string">'statistics'</span>: detailed_portfolio_statistics(optimal_weights_cvar) }, <span class="hljs-string">'Sortino'</span>: { <span class="hljs-string">'weights'</span>: optimal_weights_sortino, <span class="hljs-string">'statistics'</span>: detailed_portfolio_statistics(optimal_weights_sortino) }, <span class="hljs-string">'Variance'</span>: { <span class="hljs-string">'weights'</span>: optimal_weights_variance, <span class="hljs-string">'statistics'</span>: detailed_portfolio_statistics(optimal_weights_variance) }, <span class="hljs-string">'Sharpe'</span>: { <span class="hljs-string">'weights'</span>: optimal_weights_sharpe, <span class="hljs-string">'statistics'</span>: detailed_portfolio_statistics(optimal_weights_sharpe) }, }

<span class="hljs-comment"># Print the weights and statistics for each optimization method</span> <span class="hljs-keyword">for</span> method, data <span class="hljs-keyword">in</span> portfolio_data.items(): <span class="hljs-built_in">print</span>(<span class="hljs-string">"\n"</span>) <span class="hljs-built_in">print</span>(<span class="hljs-string">"========================================================================================================"</span>) <span class="hljs-built_in">print</span>(<span class="hljs-string">"\n"</span>) <span class="hljs-built_in">print</span>(<span class="hljs-string">f"Optimum portfolio weights for <span class="hljs-subst">{method}</span>:"</span>) <span class="hljs-built_in">print</span>(<span class="hljs-string">"\n"</span>) <span class="hljs-keyword">for</span> symbol, weight <span class="hljs-keyword">in</span> <span class="hljs-built_in">zip</span>(symbols, data[<span class="hljs-string">'weights'</span>]): <span class="hljs-keyword">if</span> weight < <span class="hljs-number">1e-4</span>: <span class="hljs-comment"># considers any weight less than 0.01% as zero</span> <span class="hljs-built_in">print</span>(<span class="hljs-string">f"<span class="hljs-subst">{symbol}</span>: practically 0%"</span>) <span class="hljs-keyword">else</span>: <span class="hljs-built_in">print</span>(<span class="hljs-string">f"<span class="hljs-subst">{symbol}</span>: <span class="hljs-subst">{weight*<span class="hljs-number">100</span>:<span class="hljs-number">.2</span>f}</span>%"</span>)

<span class="hljs-built_in">print</span>(<span class="hljs-string">"\n"</span>)
<span class="hljs-built_in">print</span>(<span class="hljs-string">f"Descriptive statistics of the optimal portfolio for <span class="hljs-subst">{method}</span>:"</span>)
<span class="hljs-built_in">print</span>(<span class="hljs-string">"\n"</span>)
<span class="hljs-keyword">for</span> name, stat <span class="hljs-keyword">in</span> <span class="hljs-built_in">zip</span>(statistics_names, data[<span class="hljs-string">'statistics'</span>]):
    <span class="hljs-built_in">print</span>(<span class="hljs-string">f"<span class="hljs-subst">{name}</span>: <span class="hljs-subst">{stat*<span class="hljs-number">100</span> <span class="hljs-keyword">if</span> name != <span class="hljs-string">'Data content'</span> <span class="hljs-keyword">else</span> stat:<span class="hljs-number">.2</span>f}</span>"</span>)

<span class="hljs-built_in">print</span>(<span class="hljs-string">"\n"</span>) <span class="hljs-built_in">print</span>(<span class="hljs-string">"========================================================================================================"</span>)</pre></div><div id="abaf"><pre>========================================================================================================

Optimum portfolio weights <span class="hljs-keyword">for</span> CVaR:

NVDA: practically <span class="hljs-number">0</span>% AMD: <span class="hljs-number">17.51</span>% MSI: <span class="hljs-number">82.49</span>% INTC: practically <span class="hljs-number">0</span>%

Descriptive statistics of the optimal portfolio <span class="hljs-keyword">for</span> CVaR:

Annualized <span class="hljs-keyword">return</span>: <span class="hljs-number">8.12</span> Annualized volatility: <span class="hljs-number">23.45</span> Skewness: <span class="hljs-number">24.53</span> Kurtosis: <span class="hljs-number">197.09</span> Max Drawdown: -<span class="hljs-number">25.46</span> Data content: <span class="hljs-number">576.00</span> Sharpe Ratio: <span class="hljs-number">34.63</span> CVaR: <span class="hljs-number">46.69</span> Sortino Ratio: <span class="hljs-number">54.29</span> Variance: <span class="hljs-number">5.50</span>

========================================================================================================

Optimum portfolio weights <span class="hljs-keyword">for</span> Sortino:

NVDA: practically <span class="hljs-number">0</span>% AMD: practically <span class="hljs-number">0</span>% MSI: <span class="hljs-number">1.76</span>% INTC: <span class="hljs-number">98.24</span>%

Descriptive statistics of the optimal portfolio <span class="hljs-keyword">for</span> Sortino:

Annualized <span class="hljs-keyword">return</span>: <span class="hljs-number">49.73</span> Annualized volatility: <span class="hljs-number">55.35</span> Skewness: <span class="hljs-number">81.96</span> Kurtosis: <span class="hljs-number">462.31</span> Max Drawdown: -<span class="hljs-number">61.07</span> Data content: <span class="hljs-number">576.00</span> Sharpe Ratio: <span class="hljs-number">89.84</span> CVaR: <span class="hljs-number">140.77</span> Sortino Ratio: <span class="hljs-number">158.52</span> Variance: <span class="hljs-number">30.64</span>

========================================================================================================

Optimum portfolio weights <span class="hljs-keyword">for</span> Variance:

NVDA: practically <span class="hljs-number">0</span>% AMD: <span class="hljs-number">16.32</span>% MSI: <span class="hljs-number">83.68</span>% INTC: practically <span class="hljs-number">0</span>%

Descriptive statistics of the optimal portfolio <span class="hljs-keyword">for</span> Variance:

Annualized <span class="hljs-keyword">return</span>: <span class="hljs-number">8.43</span> Annualized volatility: <span class="hljs-number">23.45</span> Skewness: <span class="hljs-number">24.82</span> Kurtosis: <span class="hljs-number">203.47</span> Max Drawdown: -<span class="hljs-number">25.43</span> Data content: <span class="hljs-number">576.00</span> Sharpe Ratio: <span class="hljs-number">35.94</span> CVaR: <span class="hljs-number">46.99</span> Sortino Ratio: <span class="hljs-number">56.28</span> Variance: <span class="hljs-number">5.50</span>

========================================================================================================

Optimum portfolio weights <span class="hljs-keyword">for</span> Sharpe:

NVDA: practically <span class="hljs-number">0</span>% AMD: practically <span class="hljs-number">0</span>% MSI: <span class="hljs-number">34.47</span>% INTC: <span class="hljs-number">65.53</span>%

Descriptive statistics of the optimal portfolio <span class="hljs-keyword">for</span> Sharpe:

Annualized <span class="hljs-keyword">return</span>: <span class="hljs-number">39.65</span> Annualized volatility: <span class="hljs-number">41.33</span> Skewness: <span class="hljs-number">61.72</span> Kurtosis: <span class="hljs-number">313.14</span> Max Drawdown: -<span class="hljs-number">49.28</span> Data content: <span class="hljs-number">576.00</span> Sharpe Ratio: <span class="hljs-number">95.93</span> CVaR: <span class="hljs-number">107.64</span> Sortino Ratio: <span class="hljs-number">163.20</span> Variance: <span class="hljs-number">17.08</span>

========================================================================================================</pre></div><h2 id="c7d8">Modern Port Monte Carlo Simulations</h2><ul><li>Let’s delve into the specifics of Markowitz Portfolio Optimization (<a href="https://www.kaggle.com/code/bhavinmoriya/markowitz-portfolio-optimization">MPO</a>) by employing the Monte Carlo <a href="https://mishraayush447.medium.com/portfolio-optimization-using-python-b8d2b64e520e">simulations</a> combined with relevant <a href="https://www.mlq.ai/python-for-finance-portfolio-optimization/">matplotlib</a> or <a href="https://plotly.com/python/v3/ipython-notebooks/markowitz-portfolio-optimization/">plotly</a> visualizations of the efficient frontier Markowitz-style.</li><li>Step 1: MPO data preparation</li></ul><div id="56cb"><pre><span class="hljs-comment"># Load Packages</span> <span class="hljs-keyword">import</span> numpy <span class="hljs-keyword">as</span> np <span class="hljs-keyword">import</span> pandas <span class="hljs-keyword">as</span> pd <span class="hljs-keyword">from</span> pandas_datareader <span class="hljs-keyword">import</span> data <span class="hljs-keyword">import</span> matplotlib.pyplot <span class="hljs-keyword">as</span> plt %matplotlib inline

<span class="hljs-comment"># Read Data</span> <span class="hljs-comment"># Define the ticker list</span> <span class="hljs-keyword">import</span> pandas <span class="hljs-keyword">as</span> pd tickers_list = [<span class="hljs-string">'NVDA'</span>, <span class="hljs-string">'INTC'</span>, <span class="hljs-string">'AMD'</span>, <span class="hljs-string">'MSI'</span>]

<span class="hljs-comment"># Fetch the data</span> <span class="hljs-keyword">import</span> yfinance <span class="hljs-keyword">as</span> yf data = yf.download(tickers_list,<span class="hljs-string">'2022-1-1'</span>)[<span class="hljs-string">'Adj Close'</span>]

<span class="hljs-comment"># Print last 5 rows of the data</span> <span class="hljs-built_in">print</span>(data.tail())

Ticker AMD INTC MSI NVDA Date
<span class="hljs-number">2024</span>-04-<span class="hljs-number">15</span> <span class="hljs-number">160.320007</span> <span class="hljs-number">36.310001</span> <span class="hljs-number">338.579987</span> <span class="hljs-number">860.010010</span> <span class="hljs-number">2024</span>-04-<span class="hljs-number">16</span> <span class="hljs-number">163.460007</span> <span class="hljs-number">36.259998</span> <span class="hljs-number">340.109985</span> <span class="hljs-number">874.150024</span> <span class="hljs-number">2024</span>-04-<span class="hljs-number">17</span> <span class="hljs-number">154.020004</span> <span class="hljs-number">35.680000</span> <span class="hljs-number">340.510010</span> <span class="hljs-number">840.349976</span> <span class="hljs-number">2024</span>-04-<span class="hljs-number">18</span> <span class="hljs-number">155.080002</span> <span class="hljs-number">35.040001</span> <span class="hljs-number">339.459991</span> <span class="hljs-number">846.710022</span> <span class="hljs-number">2024</span>-04-<span class="hljs-number">19</span> <span class="hljs-number">146.639999</span> <span class="hljs-number">34.200001</span> <span class="hljs-number">339.649994</span> <span class="hljs-number">762.000000</span>

<span class="hljs-comment">#Computing log return covariance and correlation matrices</span>

<span class="hljs-comment"># Log of percentage change</span> cov_matrix = data.pct_change().apply(<span class="hljs-keyword">lambda</span> x: np.log(<span class="hljs-number">1</span>+x)).cov() cov_matrix

Ticker AMD INTC MSI NVDA Ticker
AMD <span class="hljs-number">0.001175</span> <span class="hljs-number">0.000476</span> <span class="hljs-number">0.000244</span> <span class="hljs-number">0.000956</span> INTC <span class="hljs-number">0.000476</span> <span class="hljs-number">0.000606</span> <span class="hljs-number">0.000143</span> <span class="hljs-number">0.000418</span> MSI <span class="hljs-number">0.000244</span> <span class="hljs-number">0.000143</span> <span class="hljs-number">0.000232</span> <span class="hljs-number">0.000250</span> NVDA <span class="hljs-number">0.000956</span> <span class="hljs-number">0.000418</span> <span class="hljs-number">0.000250</span> <span class="hljs-number">0.001218</span>

corr_matrix = data.pct_change().apply(<span class="hljs-keyword">lambda</span> x: np.log(<span class="hljs-number">1</span>+x)).corr() corr_matrix

Ticker AMD INTC MSI NVDA Ticker
AMD <span class="hljs-number">1.000000</span> <span class="hljs-number">0.564464</span> <span class="hljs-number">0.468423</span> <span class="hljs-number">0.798755</span> INTC <span class="hljs-number">0.564464</span> <span class="hljs-number">1.000000</span> <span class="hljs-number">0.380640</span> <span class="hljs-number">0.486759</span> MSI <span class="hljs-number">0.468423</span> <span class="hljs-number">0.380640</span> <span class="hljs-number">1.000000</span> <span class="hljs-number">0.469877</span> NVDA <span class="hljs-number">0.798755</span> <span class="hljs-number">0.486759</span> <span class="hljs-number">0.469877</span> <span class="hljs-number">1.000000</span>

<span class="hljs-comment"># Volatility is given by the annual standard deviation. We multiply by 250 because there are 250 trading days/year.</span> ann_sd = data.pct_change().apply(<span class="hljs-keyword">lambda</span> x: np.log(<span class="hljs-number">1</span>+x)).std().apply(<span class="hljs-keyword">lambda</span> x: x*np.sqrt(<span class="hljs-number">250</span>)) ann_sd

Ticker AMD <span class="hljs-number">0.541973</span> INTC <span class="hljs-number">0.389105</span> MSI <span class="hljs-number">0.240755</span> NVDA <span class="hljs-number">0.551848</span> dtype: float64

<span class="hljs-comment"># Yearly returns for individual companies</span> ind_er = data.resample(<span class="hljs-string">'YE'</span>).last().pct_change().mean() ind_er

Ticker AMD <span class="hljs-number">0.635338</span> INTC <span class="hljs-number">0.314108</span> MSI <span class="hljs-number">0.159160</span> NVDA <span class="hljs-number">1.464477</span> dtype: float64

assets = pd.concat([ind_er, ann_sd], axis=<span class="hljs-number">1</span>) <span class="hljs-comment"># Creating a table for visualising returns and volatility of assets</span> assets.columns = [<span class="hljs-string">'Returns'</span>, <span class="hljs-string">'Volatility'</span>] assets

Returns Volatility

Ticker
AMD <span class="hljs-number">0.635338</span> <span class="hljs-number">0.541973</span> INTC <span class="hljs-number">0.314108</span> <span class="hljs-number">0.389105</span> MSI <span class="hljs-number">0.159160</span> <span class="hljs-number">0.240755</span> NVDA <span class="hljs-number">1.464477</span> <span class="hljs-number">0.551848</span></pre></div><ul><li>Running 10k portfolios with random weights and plotting the efficient frontier</li></ul><div id="5743"><pre>p_ret = [] <span class="hljs-comment"># Define an empty array for portfolio returns</span> p_vol = [] <span class="hljs-comment"># Define an empty array for portfolio volatility</span> p_weights = [] <span class="hljs-comment"># Define an empty array for asset weights</span>

num_assets = <span class="hljs-built_in">len</span>(data.columns) num_portfolios = <span class="hljs-number">10000</span>

<span class="hljs-keyword">for</span> portfolio <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(num_portfolios): weights = np.random.random(num_assets) weights = weights/np.<span class="hljs-built_in">sum</span>(weights) p_weights.append(weights) returns = np.dot(weights, ind_er) <span class="hljs-comment"># Returns are the product of individual expected returns of asset and its </span> <span class="hljs-comment"># weights </span> p_ret.append(returns) var = cov_matrix.mul(weights, axis=<span class="hljs-number">0</span>).mul(weights, axis=<span class="hljs-number">1</span>).<span class="hljs-built_in">sum</span>().<span class="hljs-built_in">sum</span>()<span class="hljs-comment"># Portfolio Variance</span> sd = np.sqrt(var) <span class="hljs-comment"># Daily standard deviation</span> ann_sd = sd*np.sqrt(<span class="hljs-number">250</span>) <span class="hljs-comment"># Annual standard deviation = volatility</span> p_vol.append(ann_sd)

data1 = {<span class="hljs-string">'Returns'</span>:p_ret, <span class="hljs-string">'Volatility'</span>:p_vol}

<span class="hljs-keyword">for</span> counter, symbol <span class="hljs-keyword">in</span> <span class="hljs-built_in">enumerate</span>(data.columns.tolist()): <span class="hljs-comment">#print(counter, symbol)</span> data1[symbol+<span class="hljs-string">' weight'</span>] = [w[counter] <span class="hljs-keyword">for</span> w <span class="hljs-keyword">in</span> p_weights]

portfolios = pd.DataFrame(data1) portfolios.tail() <span class="hljs-comment"># Dataframe of the 10000 portfolios created</span>

Returns Volatility AMD weight INTC weight MSI weight NVDA weight <span class="hljs-number">9995</span> <span class="hljs-number">0.771793</span> <span class="hljs-number">0.405336</span> <span class="hljs-number">0.318910</span> <span class="hljs-number">0.208203</span> <span class="hljs-number">0.144603</span> <span class="hljs-number">0.328284</span> <span class="hljs-number">9996</span> <span class="hljs-number">0.852389</span> <span class="hljs-number">0.392365</span> <span class="hljs-number">0.130841</span> <span class="hljs-number">0.255292</span> <span class="hljs-number">0.160822</span> <span class="hljs-number">0.453046</span> <span class="hljs-number">9997</span> <span class="hljs-number">0.665961</span> <span class="hljs-number">0.378391</span> <span class="hljs-number">0.295835</span> <span class="hljs-number">0.288311</span> <span class="hljs-number">0.169740</span> <span class="hljs-number">0.246115</span> <span class="hljs-number">9998</span> <span class="hljs-number">0.801484</span> <span class="hljs-number">0.383952</span> <span class="hljs-number">0.222032</span> <span class="hljs-number">0.066961</span> <span class="hljs-number">0.307869</span> <span class="hljs-number">0.403137</span> <span class="hljs-number">9999</span> <span class="hljs-number">0.676878</span> <span class="hljs-number">0.429700</span> <span class="hljs-number">0.505008</span> <span class="hljs-number">0.247905</span> <span class="hljs-number">0.064119</span> <span class="hljs-number">0.182969</span>

<span class="hljs-comment"># Plot efficient frontier</span> portfolios.plot.scatter(x=<span class="hljs-string">'Volatility'</span>, y=<span class="hljs-string">'Returns'</span>, marker=<span class="hljs-string">'o'</span>, s=<span class="hljs-number">10</span>, alpha=<span class="hljs-number">0.3</span>, grid=<span class="hljs-literal">True</span>, figsize=[<span class="hljs-number">5</span>,<span class="hljs-number">5</span>])</pre></div><figure id="b7f1"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*_6HBm0lz2VCQBWoJpCfqcw.png"><figcaption>Efficient frontier of 10k random portfolios</figcaption></figure><ul><li>Creating the minimum Volatility portfolio</li></ul><div id="d63c"><pre>min_vol_port = portfolios.iloc[portfolios[<span class="hljs-string">'Volatility'</span>].idxmin()] <span class="hljs-comment"># idxmin() gives us the minimum value in the column specified. </span> min_vol_port Returns <span class="hljs-number">0.222657</span> Volatility <span class="hljs-number">0.235856</span> AMD weight <span class="hljs-number">0.005248</span> INTC weight <span class="hljs-number">0.146243</span> MSI weight <span class="hljs-number">0.819138</span> NVDA weight <span class="hljs-number">0.029371</span> Name: <span class="hljs-number">7829</span>, dtype: float64

<span class="hljs-comment"># plotting the minimum volatility portfolio</span> plt.subplots(figsize=[<span class="hljs-number">7</span>,<span class="hljs-number">7</span>]) plt.scatter(portfolios[<span class="hljs-string">'Volatility'</span>], portfolios[<span class="hljs-string">'Returns'</span>],marker=<span class="hljs-string">'o'</span>, s=<span class="hljs-number">10</span>, alpha=<span class="hljs-number">0.3</span>) plt.scatter(min_vol_port[<span class="hljs-number">1</span>], min_vol_port[<span class="hljs-number">0</span>], color=<span class="hljs-string">'r'</span>, marker=<span class="hljs-string">'*'</span>, s=<span class="hljs-number">500</span>) plt.xlabel(<span class="hljs-string">'Volatility'</span>,fontsize=<span class="hljs-number">14</span>) plt.ylabel(<span class="hljs-string">'Returns'</span>,fontsize=<span class="hljs-number">14</span>) plt.title(<span class="hljs-string">"Minimum Volatility Portfolio"</span>,fontsize=<span class="hljs-number">16</span>) plt.grid()</pre></div><figure id="6197"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*al01Hbg1-1muf2NnEFYveg.png"><figcaption>Minimum Volatility portfolio</figcaption></figure><ul><li>Finding the optimal portfolio max Sharpe</li></ul><div id="6690"><pre><span class="hljs-comment"># Finding the optimal portfolio max Sharpe</span> rf = <span class="hljs-number">0.01</span> <span class="hljs-comment"># risk factor</span> optimal_risky_port = portfolios.iloc[((portfolios[<span class="hljs-string">'Returns'</span>]-rf)/portfolios[<span class="hljs-string">'Volatility'</span>]).idxmax()] optimal_risky_port

Returns <span class="hljs-number">1.320434</span> Volatility <span class="hljs-number">0.507973</span> AMD weight <span class="hljs-number">0.020084</span> INTC weight <span class="hljs-number">0.033438</span> MSI weight <span class="hljs-number">0.068125</span> NVDA weight <span class="hljs-number">0.878353</span> Name: <span class="hljs-number">5210</span>, dtype: float64</pre></div><ul><li>Plotting both portfolios and the efficient frontier</li></ul><div id="e909"><pre><span class="hljs-comment"># Plotting optimal portfolio</span> plt.subplots(figsize=(<span class="hljs-number">8</span>, <span class="hljs-number">8</span>)) plt.scatter(portfolios[<span class="hljs-string">'Volatility'</span>], portfolios[<span class="hljs-string">'Returns'</span>],marker=<span class="hljs-string">'o'</span>, s=<span class="hljs-number">10</span>, alpha=<span class="hljs-number">0.3</span>) plt.scatter(min_vol_port[<span class="hljs-number">1</span>], min_vol_port[<span class="hljs-number">0</span>], color=<span class="hljs-string">'r'</span>, marker=<span class="hljs-string">''</span>, s=<span class="hljs-number">500</span>) plt.scatter(optimal_risky_port[<span class="hljs-number">1</span>], optimal_risky_port[<span class="hljs-number">0</span>], color=<span class="hljs-string">'g'</span>, marker=<span class="hljs-string">''</span>, s=<span class="hljs-number">500</span>) plt.xlabel(<span class="hljs-string">'Volatility'</span>,fontsize=<span class="hljs-number">14</span>) plt.ylabel(<span class="hljs-string">'Returns'</span>,fontsize=<span class="hljs-number">14</span>) plt.title(<span class="hljs-string">"Minimum Volatility (Red) vs Optimal Risky (Green) Portfolio"</span>,fontsize=<span class="hljs-number">14</span>) plt.grid()</pre></div><figure id="13fd"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*5vKEO3tuBU-mzlQVIp3HUw.png"><figcaption>Minimum Volatility, max Sharpe portfolios and the efficient frontier.</figcaption></figure><h2 id="3c4b">Monte Carlo vs SciPy 2Y MPO</h2><ul><li>In this section, we will focus on the MPO-based return and risk<b> </b>of our 2Y tech stock portfolio. By implementing both <a href="https://www.kaggle.com/code/bhavinmoriya/markowitz-portfolio-optimization">SciPy Opt and the Monte Carlo Method</a>, we can create a more accurate optimization process compared to <a href="https://fastercapital.com/topics/the-limitations-of-traditional-portfolio-optimization-techniques.html">traditional methods</a>.</li></ul><div id="2b74"><pre><span class="hljs-comment"># Load Packages</span> <span class="hljs-keyword">import</span> numpy <span class="hljs-keyword">as</span> np <span class="hljs-keyword">import</span> pandas <span class="hljs-keyword">as</span> pd <span class="hljs-keyword">import</span> matplotlib.pyplot <span class="hljs-keyword">as</span> plt <span class="hljs-keyword">import</span> plotly.express <span class="hljs-keyword">as</span> px <span class="hljs-keyword">import</span> pandas_datareader <span class="hljs-keyword">as</span> web <span class="hljs-keyword">from</span> datetime <span class="hljs-keyword">import</span> datetime <span class="hljs-keyword">as</span> dt, timedelta <span class="hljs-keyword">as</span> td

end = dt.today() start = end - td(days=<span class="hljs-number">2</span>*<span class="hljs-number">365</span>)

<span class="hljs-comment">#option 1</span> stocks = [<span class="hljs-string">'NVDA'</span>, <span class="hljs-string">'INTC'</span>, <span class="hljs-string">'AMD'</span>, <span class="hljs-string">'MSI'</span>,<span class="hljs-string">'^GSPC'</span>] <span class="hljs-comment">#option 2</span> stocks = [<span class="hljs-string">'NVDA'</span>, <span class="hljs-string">'INTC'</span>, <span class="hljs-string">'AMD'</span>, <span class="hljs-string">'MSI'</span>]

<span class="hljs-comment"># Fetch the data</span> <span class="hljs-keyword">import</span> yfinance <span class="hljs-keyword">as</span> yf df = yf.download(stocks,start=start,end=end)[<span class="hljs-string">'Adj Close'</span>]</pre></div><ul><li>Plotting the normalized stock prices scaled by 100</li></ul><div id="db18"><pre>px.line(df * <span class="hljs-number">100</span> / df.iloc[<span class="hljs-number">0</span>]) <span class="hljs-comment">#cf. Stock Returns vs Benchmark</span></pre></div><ul><li>Plotting the daily percentage changes</li></ul><div id="2ec6"><pre>ret_port = df.pct_change() px.line(ret_port) <span class="hljs-comment">#cf. Stock Returns vs Benchmark</span></pre></div><ul><li>Plotting the stock cumulative return</li></ul><div id="7174"><pre>cumretport = (<span class="hljs-number">1</span> + ret_port).cumprod() - <span class="hljs-number">1</span> px.line(cumretport*<span class="hljs-number">100</span>) <span class="hljs-comment">#cf. Stock Returns vs Benchmark</span></pre></div><div id="7e8a"><pre><span class="hljs-built_in">print</span>(log_ret.mean()) <span class="hljs-comment"># option 1</span>

Ticker AMD <span class="hljs-number">0.001018</span> INTC -<span class="hljs-number">0.000502</span> MSI <span class="hljs-number">0.000876</span> NVDA <span class="hljs-number">0.002727</span> ^GSPC <span class="hljs-number">0.000302</span> dtype: float64</pre></div><ul><li>Calculating the expected return and volatility for 1k random portfolios (cf. option 2)</li></ul><div id="245f"><pre>np.random.seed(<span class="hljs-number">1</span>) <span class="hljs-comment"># Weight each security</span> weights = np.random.random((<span class="hljs-number">4</span>,<span class="hljs-number">1</span>)) <span class="hljs-comment"># normalize it, so that some is one</span> weights /= np.<span class="hljs-built_in">sum</span>(weights) <span class="hljs-built_in">print</span>(<span class="hljs-string">f'Normalized Weights : <span class="hljs-subst">{weights.flatten()}</span>'</span>)

<span class="hljs-comment"># We generally do log return instead of return</span> log_ret = np.log(df / df.shift(<span class="hljs-number">1</span>)) log_ret

<span class="hljs-comment"># Expected return (weighted sum of mean returns). Mult by 252 as we always do annual calculation and year has 252 business days</span> exp_ret = log_ret.mean()[:-<span class="hljs-number">1</span>].dot(weights)*<span class="hljs-number">252</span> <span class="hljs-built_in">print</span>(<span class="hljs-string">f'\nExpected return of the portfolio is : <span class="hljs-subst">{exp_ret[<span class="hljs-number">0</span>]}</span>'</span>)

<span class="hljs-comment"># Exp Volatility (Risk)</span> exp_vol = np.sqrt(weights.T.dot(<span class="hljs-number">252</span>*log_ret.cov().dot(weights))) <span class="hljs-built_in">print</span>(<span class="hljs-string">f'\nVolatility of the portfolio: <span class="hljs-subst">{exp_vol[<span class="hljs-number">0</span>][<span class="hljs-number">0</span>]}</span>'</span>)

<span class="hljs-comment"># Sharpe ratio</span> sr = exp_ret / exp_vol <span class="hljs-built_in">print</span>(<span class="hljs-string">f'\nSharpe ratio of the portfolio: <span class="hljs-subst">{sr[<span class="hljs-number">0</span>][<span class="hljs-number">0</span>]}</span>'</span>)

Normalized Weights : [<span class="hljs-number">2.89640161e-01</span> <span class="hljs-number">5.00297106e-01</span> <span class="hljs-number">7.94383512e-05</span> <span class="hljs-number">2.09983296e-01</span>]

<span class="hljs-comment"># number of simulations</span> n = <span class="hljs-number">1000</span>

port_weights = np.zeros(shape=(n,<span class="hljs-built_in">len</span>(df.columns))) port_volatility = np.zeros(n) port_sr = np.zeros(n) port_return = np.zeros(n)

num_securities = <span class="hljs-built_in">len</span>(df.columns) <span class="hljs-comment"># num_securities</span> <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(n): <span class="hljs-comment"># Weight each security</span> weights = np.random.random(<span class="hljs-number">4</span>) <span class="hljs-comment"># normalize it, so that some is one</span> weights /= np.<span class="hljs-built_in">sum</span>(weights) port_weights[i,:] = weights <span class="hljs-comment"># print(f'Normalized Weights : {weights.flatten()}')</span>

<span class="hljs-comment"># Expected return (weighted sum of mean returns). Mult by 252 as we always do annual calculation and year has 252 business days</span>
exp_ret = log_ret.mean().dot(weights)*<span class="hljs-number">252</span> 
port_return[i] = exp_ret

<span class="hljs-comment"># print(f'\nExpected return is : {exp_ret[0]}')</span>

<span class="hljs-comment"># Exp Volatility (Risk)</span>
exp_vol = np.sqrt(weights.T.dot(<span class="hljs-number">252</span>*log_ret.cov().dot(weights)))
port_volatility[i] = exp_vol

<span class="hljs-comment"># print(f'\nVolatility : {exp_vol[0][0]}')</span>

<span class="hljs-comment"># Sharpe ratio</span>
sr = exp_ret / exp_vol
port_sr[i] = sr

<span class="hljs-comment"># print(f'\nSharpe ratio : {sr[0][0]}')</span> </pre></div><ul><li>Finding the return and volatility at max Sharpe Ratio (SR)</li></ul><div id="d81a"><pre><span class="hljs-comment"># Index of max Sharpe Ratio</span> max_sr = port_sr.<span class="hljs-built_in">max</span>() ind = port_sr.argmax() <span class="hljs-comment"># Return and Volatility at Max SR</span> max_sr_ret = port_return[ind] max_sr_vol = port_volatility[ind]</pre></div><ul><li>Plotting the efficient frontier and the max SR portfolio</li></ul><div id="4845"><pre>plt.figure(figsize=(<span class="hljs-number">10</span>,<span class="hljs-number">6</span>)) plt.scatter(port_volatility,port_return,c=port_sr, cmap=<span class="hljs-string">'plasma'</span>) plt.colorbar(label=<span class="hljs-string">'Sharpe Ratio'</span>) plt.xlabel(<span class="hljs-string">'Volatility'</span>, fontsize=<span class="hljs-number">15</span>) plt.ylabel(<span class="hljs-string">'Return'</span>, fontsize=<span class="hljs-number">15</span>) plt.title(<span class="hljs-string">'Efficient Frontier (Bullet Plot)'</span>, fontsize=<span class="hljs-number">15</span>) plt.scatter(max_sr_vol, max_sr_ret, c=<span class="hljs-string">'blue'</span>, s=<span class="hljs-number">150</span>, edgecolors=<span class="hljs-string">'red'</span>, marker=<span class="hljs-string">'o'</span>, label=<span class="hljs-string">'Max
Sharpe Ratio Portfolio'</span>) plt.legend();</pre></div><figure id="1102"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*wfHqn668dYV2vCzL8eO1Hg.png"><figcaption>Efficient frontier and the max Sharpe Ratio portfolio</figcaption></figure><ul><li>Optimized portfolio weights, expected returns and volatility</li></ul><div id="3f60"><pre><span class="hljs-keyword">for</span> weight, stock <span class="hljs-keyword">in</span> <span class="hljs-built_in">zip</span>(port_weights[ind],stocks): <span class="hljs-built_in">print</span>(<span class="hljs-string">f'<span class="hljs-subst">{<span class="hljs-built_in">round</span>(weight * <span class="hljs-number">100</span>, <span class="hljs-number">2</span>)}</span> % of <span class="hljs-subst">{stock}</span> should be bought.'</span>)

<span class="hljs-comment"># best portfolio return option 2</span> <span class="hljs-built_in">print</span>(<span class="hljs-string">f'\nMarkowitz optimal portfolio return is : <span class="hljs-subst">{<span class="hljs-built_in">round</span>(max_sr_ret * <span class="hljs-number">100</span>, <span class="hljs-number">2</span>)}</span>% with volatility
<span class="hljs-subst">{max_sr_vol}</span>'</span>)

<span class="hljs-number">5.69</span> % of NVDA should be bought. <span class="hljs-number">1.35</span> % of INTC should be bought. <span class="hljs-number">38.94</span> % of AMD should be bought. <span class="hljs-number">54.02</span> % of MSI should be bought.

Markowitz optimal portfolio <span class="hljs-keyword">return</span> <span class="hljs-keyword">is</span> : <span class="hljs-number">45.45</span>% <span class="hljs-keyword">with</span> volatility <span class="hljs-number">0.3632750947781604</span></pre></div><ul><li>Using SciPy to get the max of Sharpe Ratio</li></ul><div id="5049"><pre><span class="hljs-comment">#SciPy to get the max of Sharpe Ratio</span> <span class="hljs-keyword">from</span> scipy <span class="hljs-keyword">import</span> optimize log_mean = log_ret.mean() * <span class="hljs-number">252</span> cov = log_ret.cov() * <span class="hljs-number">252</span>

<span class="hljs-comment"># Some helper functions</span> <span class="hljs-keyword">def</span> <span class="hljs-title function_">get_ret_vol_sr</span>(<span class="hljs-params">weights</span>): weights = np.array(weights) ret = log_mean.dot(weights) vol = np.sqrt(weights.T.dot(cov.dot(weights))) sr = ret / vol <span class="hljs-keyword">return</span> np.array([ret, vol, sr])

<span class="hljs-comment"># Negate Sharpe ratio as we need to max it but Scipy minimize the given function</span> <span class="hljs-keyword">def</span> <span class="hljs-title function_">neg_sr</span>(<span class="hljs-params">weights</span>): <span class="hljs-keyword">return</span> get_ret_vol_sr(weights)[-<span class="hljs-number">1</span>] * -<span class="hljs-number">1</span>

<span class="hljs-comment"># check sum of weights </span> <span class="hljs-keyword">def</span> <span class="hljs-title function_">check_sum</span>(<span class="hljs-params">weights</span>): <span class="hljs-keyword">return</span> np.<span class="hljs-built_in">sum</span>(weights) - <span class="hljs-number">1</span>

<span class="hljs-comment"># Constraints for the optimization problem</span> cons = {<span class="hljs-string">'type'</span>:<span class="hljs-string">'eq'</span>,<span class="hljs-string">'fun'</span>:check_sum} <span class="hljs-comment"># bounds on weights</span> bounds = ((<span class="hljs-number">0</span>,<span class="hljs-number">1</span>),(<span class="hljs-number">0</span>,<span class="hljs-number">1</span>),(<span class="hljs-number">0</span>,<span class="hljs-number">1</span>),(<span class="hljs-number">0</span>,<span class="hljs-number">1</span>)) <span class="hljs-comment"># initial guess for optimization to start with</span> init_guess = [<span class="hljs-number">.25</span> <span class="hljs-keyword">for</span> _ <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">4</span>)]

<span class="hljs-comment"># Call minimizer</span> opt_results = optimize.minimize(neg_sr, init_guess, constraints=cons, bounds=bounds, method=<span class="hljs-string">'SLSQP'</span>)

optimal_weights = opt_results.x <span class="hljs-comment"># optimal_weights</span> <span class="hljs-keyword">for</span> st, i <span class="hljs-keyword">in</span> <span class="hljs-built_in">zip</span>(stocks,optimal_weights): <span class="hljs-built_in">print</span>(<span class="hljs-string">f'Stock <span class="hljs-subst">{st}</span> has weight <span class="hljs-subst">{np.<span class="hljs-built_in">round</span>(i*<span class="hljs-number">100</span>,<span class="hljs-number">2</span>)}</span> %'</span>)

Stock NVDA has weight <span class="hljs-number">0.0</span> % Stock INTC has weight <span class="hljs-number">0.0</span> % Stock AMD has weight <span class="hljs-number">47.28</span> % Stock MSI has weight <span class="hljs-number">52.72</span> %

<span class="hljs-comment">#Monte Carlo weights</span>

mc_weights = port_weights[ind] <span class="hljs-keyword">for</span> st, i <span class="hljs-keyword">in</span> <span class="hljs-built_in">zip</span>(stocks,mc_weights): <span class="hljs-built_in">print</span>(<span class="hljs-string">f'Stock <span class="hljs-subst">{st}</span> has weight <span class="hljs-subst">{np.<span class="hljs-built_in">round</span>(i*<span class="hljs-number">100</span>,<span class="hljs-number">2</span>)}</span> %'</span>)

Stock NVDA has weight <span class="hljs-number">5.69</span> % Stock INTC has weight <span class="hljs-number">1.35</span> % Stock AMD has weight <span class="hljs-number">38.94</span> % Stock MSI has weight <span class="hljs-number">54.02</span> %

<span class="hljs-comment"># Comparing two results we see that we get very close results</span> (optimal_weights - mc_weights)

array([-<span class="hljs-number">0.05690935</span>, -<span class="hljs-number">0.01352879</span>, <span class="hljs-number">0.08342671</span>, -<span class="hljs-number">0.01298856</span>])</pre></div><ul><li>Comparing expected returns and volatility</li></ul><div id="b552"><pre>get_ret_vol_sr(optimal_weights), get_ret_vol_sr(mc_weights)

<span class="hljs-built_in">print</span>(<span class="hljs-string">'For a given portfolio we have: (Using SciPy optimizer)\n \n'</span>) <span class="hljs-keyword">for</span> i, j <span class="hljs-keyword">in</span> <span class="hljs-built_in">enumerate</span>(<span class="hljs-string">'Return Volatility SharpeRatio'</span>.split()): <span class="hljs-built_in">print</span>(<span class="hljs-string">f'<span class="hljs-subst">{j}</span> is : <span class="hljs-subst">{get_ret_vol_sr(optimal_weights)[i]}</span>\n'</span>)

<span class="hljs-built_in">print</span>(<span class="hljs-string">'For a given portfolio we have: (Using Monte Carlo)\n \n'</span>) <span class="hljs-keyword">for</span> i, j <span class="hljs-keyword">in</span> <span class="hljs-built_in">enumerate</span>(<span class="hljs-string">'Return Volatility SharpeRatio'</span>.split()): <span class="hljs-built_in">print</span>(<span class="hljs-string">f'<span class="hljs-subst">{j}</span> is : <span class="hljs-subst">{get_ret_vol_sr(mc_weights)[i]}</span>\n'</span>)

For a given portfolio we have: (Using SciPy optimizer)

Return <span class="hljs-keyword">is</span> : <span class="hljs-number">0.45084758839098316</span>

Volatility <span class="hljs-keyword">is</span> : <span class="hljs-number">0.34220896907233184</span>

SharpeRatio <span class="hljs-keyword">is</span> : <span class="hljs-number">1.3174628052945294</span>

For a given portfolio we have: (Using Monte Carlo)

Return <span class="hljs-keyword">is</span> : <span class="hljs-number">0.45447440930271593</span>

Volatility <span class="hljs-keyword">is</span> : <span class="hljs-number">0.3632750947781604</span>

SharpeRatio <span class="hljs-keyword">is</span> : <span class="hljs-number">1.2510475279904554</span></pre></div><ul><li>Plotting the efficient frontier curve vs max SR portfolio</li></ul><div id="b33a"><pre><span class="hljs-comment">#Frontier curve</span> <span class="hljs-comment">#Best return for given volatility or vice versa.</span> frontier_y = np.linspace(port_return.<span class="hljs-built_in">min</span>(), port_return.<span class="hljs-built_in">max</span>(), <span class="hljs-number">100</span>) frontier_vol = []

<span class="hljs-keyword">def</span> <span class="hljs-title function_">minimize_vol</span>(<span class="hljs-params">weights</span>): <span class="hljs-keyword">return</span> get_ret_vol_sr(weights)[<span class="hljs-number">1</span>]

<span class="hljs-keyword">for</span> possible_ret <span class="hljs-keyword">in</span> frontier_y: cons = ({<span class="hljs-string">'type'</span>:<span class="hljs-string">'eq'</span>,<span class="hljs-string">'fun'</span>:check_sum}, {<span class="hljs-string">'type'</span>:<span class="hljs-string">'eq'</span>,<span class="hljs-string">'fun'</span>:<span class="hljs-keyword">lambda</span> w:get_ret_vol_sr(w)[<span class="hljs-number">0</span>] - possible_ret}) result = optimize.minimize(minimize_vol, init_guess, method=<span class="hljs-string">'SLSQP'</span>, constraints=cons, bounds=bounds) frontier_vol.append(result[<span class="hljs-string">'fun'</span>])

plt.figure(figsize=(<span class="hljs-number">10</span>,<span class="hljs-number">6</span>)) plt.scatter(port_volatility,port_return,c=port_sr, cmap=<span class="hljs-string">'plasma'</span>) plt.colorbar(label=<span class="hljs-string">'Sharpe Ratio'</span>) plt.xlabel(<span class="hljs-string">'Volatility'</span>, fontsize=<span class="hljs-number">15</span>) plt.ylabel(<span class="hljs-string">'Return'</span>, fontsize=<span class="hljs-number">15</span>) plt.title(<span class="hljs-string">'Efficient Frontier'</span>, fontsize=<span class="hljs-number">15</span>) plt.scatter(max_sr_vol, max_sr_ret, c=<span class="hljs-string">'blue'</span>, s=<span class="hljs-number">150</span>, edgecolors=<span class="hljs-string">'red'</span>, marker=<span class="hljs-string">'o'</span>)

plt.plot(frontier_vol, frontier_y, c=<span class="hljs-string">'magenta'</span>, ls=<span class="hljs-string">'--'</span>, lw=<span class="hljs-number">3</span>, label=<span class="hljs-string">'Efficient Frontier'</span>) plt.legend();</pre></div><figure id="75c2"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*H6I7HlOWXUXYFoNQzezbiA.png"><figcaption>Efficient frontier curve vs max SR portfolio</figcaption></figure><h2 id="62d9">Quantstats Portfolio Report Before MPO</h2><ul><li>We employ <a href="https://github.com/ranaroussi/quantstats">Quantstats</a> to understand portfolio performance better by examining in-depth analytics and risk metrics vs ^GSPC.</li><li>Our initial portfolio consists of 4 tech stocks (option 2) with equal weights 0.25, viz.</li></ul><div id="4313"><pre>weights = [<span class="hljs-number">0.25</span>, <span class="hljs-number">0.25</span>, <span class="hljs-number">0.25</span>, <span class="hljs-number">0.25</span>] <span class="hljs-comment"># Defining weights for each stock</span> portfolio = df[<span class="hljs-string">'NVDA'</span>]*weights[<span class="hljs-number">0</span>] + df[<span class="hljs-string">'AMD'</span>]*weights[<span class="hljs-number">1</span>] + df[<span class="hljs-string">'INTC'</span>]*weights[<span class="hljs-number">2</span>] + df[<span class="hljs-string">'MSI'</span>]*weights[<span class="hljs-number">3</span>] <span class="hljs-comment"># Creating portfolio multiplying each stock for its respective weight </span> portfolio <span class="hljs-comment"># Portfolio before MPO</span>

Date <span class="hljs-number">2022</span>-04-<span class="hljs-number">19</span> <span class="hljs-number">148.027820</span> <span class="hljs-number">2022</span>-04-<span class="hljs-number">20</span> <span class="hljs-number">146.227382</span> <span class="hljs-number">2022</span>-04-<span class="hljs-number">21</span> <span class="hljs-number">140.810877</span> <span class="hljs-number">2022</span>-04-<span class="hljs-number">22</span> <span class="hljs-number">136.540077</span> <span class="hljs-number">2022</span>-04-<span class="hljs-number">25</span> <span class="hljs-number">138.295864</span> ...
<span class="hljs-number">2024</span>-04-<span class="hljs-number">12</span> <span class="hljs-number">356.159995</span> <span class="hljs-number">2024</span>-04-<span class="hljs-number">15</span> <span class="hljs-number">348.805001</span> <span class="hljs-number">2024</span>-04-<span class="hljs-number">16</span> <span class="hljs-number">353.495004</span> <span class="hljs-number">2024</span>-04-<span class="hljs-number">17</span> <span class="hljs-number">342.639997</span> <span class="hljs-number">2024</span>-04-<span class="hljs-number">18</span> <span class="hljs-number">347.843740</span> Length: <span class="hljs-number">503</span>, dtype: float64</pre></div><ul><li>Plotting the full portfolio report vs ^GSPC benchmark</li></ul><div id="827a"><pre>qs.reports.full(portfolio, benchmark = df[<span class="hljs-string">'^GSPC'</span>])

Performance Metrics

                       Benchmark    Strategy

Start Period <span class="hljs-number">2022</span>-04-<span class="hljs-number">20</span> <span class="hljs-number">2022</span>-04-<span class="hljs-number">20</span> End Period <span class="hljs-number">2024</span>-04-<span class="hljs-number">18</span> <span class="hljs-number">2024</span>-04-<span class="hljs-number">18</span> Risk-Free Rate <span class="hljs-number">0.0</span>% <span class="hljs-number">0.0</span>% Time <span class="hljs-keyword">in</span> Market <span class="hljs-number">100.0</span>% <span class="hljs-number">100.0</span>%

Cumulative Return <span class="hljs-number">13.12</span>% <span class="hljs-number">134.99</span>% CAGR﹪ <span class="hljs-number">4.35</span>% <span class="hljs-number">34.36</span>%

Sharpe <span class="hljs-number">0.43</span> <span class="hljs-number">1.41</span> Prob. Sharpe Ratio <span class="hljs-number">72.72</span>% <span class="hljs-number">97.91</span>% Smart Sharpe <span class="hljs-number">0.42</span> <span class="hljs-number">1.37</span> Sortino <span class="hljs-number">0.61</span> <span class="hljs-number">2.26</span> Smart Sortino <span class="hljs-number">0.6</span> <span class="hljs-number">2.19</span> Sortino/√<span class="hljs-number">2</span> <span class="hljs-number">0.43</span> <span class="hljs-number">1.6</span> Smart Sortino/√<span class="hljs-number">2</span> <span class="hljs-number">0.42</span> <span class="hljs-number">1.55</span> Omega <span class="hljs-number">1.27</span> <span class="hljs-number">1.27</span>

Max Drawdown -<span class="hljs-number">19.79</span>% -<span class="hljs-number">31.21</span>% Longest DD Days <span class="hljs-number">447</span> <span class="hljs-number">287</span> Volatility (ann.) <span class="hljs-number">18.32</span>% <span class="hljs-number">34.63</span>% R^<span class="hljs-number">2</span> <span class="hljs-number">0.64</span> <span class="hljs-number">0.64</span> Information Ratio <span class="hljs-number">0.11</span> <span class="hljs-number">0.11</span> Calmar <span class="hljs-number">0.22</span> <span class="hljs-number">1.1</span> Skew -<span class="hljs-number">0.11</span> <span class="hljs-number">0.55</span> Kurtosis <span class="hljs-number">2.03</span> <span class="hljs-number">2.88</span>

Expected Daily % <span class="hljs-number">0.02</span>% <span class="hljs-number">0.17</span>% Expected Monthly % <span class="hljs-number">0.49</span>% <span class="hljs-number">3.48</span>% Expected Yearly % <span class="hljs-number">4.2</span>% <span class="hljs-number">32.95</span>% Kelly Criterion <span class="hljs-number">1.98</span>% <span class="hljs-number">12.12</span>% Risk of Ruin <span class="hljs-number">0.0</span>% <span class="hljs-number">0.0</span>% Daily Value-at-Risk -<span class="hljs-number">1.87</span>% -<span class="hljs-number">3.39</span>% Expected Shortfall (cVaR) -<span class="hljs-number">1.87</span>% -<span class="hljs-number">3.39</span>%

Max Consecutive Wins <span class="hljs-number">8</span> <span class="hljs-number">11</span> Max Consecutive Losses <span class="hljs-number">6</span> <span class="hljs-number">7</span> Gain/Pain Ratio <span class="hljs-number">0.08</span> <span class="hljs-number">0.27</span> Gain/Pain (1M) <span class="hljs-number">0.31</span> <span class="hljs-number">1.27</span>

Payoff Ratio <span class="hljs-number">1.03</span> <span class="hljs-number">1.16</span> Profit Factor <span class="hljs-number">1.08</span> <span class="hljs-number">1.27</span> Common Sense Ratio <span class="hljs-number">1.24</span> <span class="hljs-number">1.6</span> CPC Index <span class="hljs-number">0.56</span> <span class="hljs-number">0.78</span> Tail Ratio <span class="hljs-number">1.15</span> <span class="hljs-number">1.26</span> Outlier Win Ratio <span class="hljs-number">4.82</span> <span class="hljs-number">2.45</span> Outlier Loss Ratio <span class="hljs-number">5.33</span> <span class="hljs-number">2.88</span>

MTD -<span class="hljs-number">3.93</span>% -<span class="hljs-number">6.19</span>% 3M <span class="hljs-number">6.51</span>% <span class="hljs-number">28.51</span>% 6M <span class="hljs-number">15.42</span>% <span class="hljs-number">60.21</span>% YTD <span class="hljs-number">5.83</span>% <span class="hljs-number">38.46</span>% 1Y <span class="hljs-number">21.59</span>% <span class="hljs-number">104.94</span>% 3Y (ann.) <span class="hljs-number">4.35</span>% <span class="hljs-number">34.36</span>% 5Y (ann.) <span class="hljs-number">4.35</span>% <span class="hljs-number">34.36</span>% 10Y (ann.) <span class="hljs-number">4.35</span>% <span class="hljs-number">34.36</span>% All-time (ann.) <span class="hljs-number">4.35</span>% <span class="hljs-number">34.36</span>%

Best Day <span class="hljs-number">5.54</span>% <span class="hljs-number">11.53</span>% Worst Day -<span class="hljs-number">4.32</span>% -<span class="hljs-number">6.06</span>% Best Month <span class="hljs-number">9.11</span>% <span class="hljs-number">18.49</span>% Worst Month -<span class="hljs-number">9.34</span>% -<span class="hljs-number">14.91</span>% Best Year <span class="hljs-number">24.23</span>% <span class="hljs-number">104.95</span>% Worst Year -<span class="hljs-number">13.96</span>% -<span class="hljs-number">17.19</span>%

Avg. Drawdown -<span class="hljs-number">2.28</span>% -<span class="hljs-number">3.72</span>% Avg. Drawdown Days <span class="hljs-number">30</span> <span class="hljs-number">18</span> Recovery Factor <span class="hljs-number">0.79</span> <span class="hljs-number">3.12</span> Ulcer Index <span class="hljs-number">0.09</span> <span class="hljs-number">0.1</span> Serenity Index <span class="hljs-number">0.13</span> <span class="hljs-number">1.12</span>

Avg. Up Month <span class="hljs-number">4.66</span>% <span class="hljs-number">11.94</span>% Avg. Down Month -<span class="hljs-number">5.78</span>% -<span class="hljs-number">9.36</span>% Win Days % <span class="hljs-number">50.2</span>% <span class="hljs-number">52.79</span>% Win Month % <span class="hljs-number">60.0</span>% <span class="hljs-number">64.0</span>% Win Quarter % <span class="hljs-number">55.56</span>% <span class="hljs-number">55.56</span>% Win Year % <span class="hljs-number">66.67</span>% <span class="hljs-number">66.67</span>%

Beta - <span class="hljs-number">1.52</span> Alpha - <span class="hljs-number">0.37</span> Correlation - <span class="hljs-number">80.15</span>% Treynor Ratio - <span class="hljs-number">89.09</span>% <span class="hljs-literal">None</span> Worst <span class="hljs-number">5</span> Drawdowns Start Valley End Days Max Drawdown <span class="hljs-number">99</span>% Max Drawdown <span class="hljs-number">1</span> <span class="hljs-number">2022</span>-04-<span class="hljs-number">21</span> <span class="hljs-number">2022</span>-<span class="hljs-number">10</span>-<span class="hljs-number">14</span> <span class="hljs-number">2023</span>-02-01 <span class="hljs-number">287</span> -<span class="hljs-number">31.213813</span> -<span class="hljs-number">28.614034</span> <span class="hljs-number">2</span> <span class="hljs-number">2023</span>-09-01 <span class="hljs-number">2023</span>-<span class="hljs-number">10</span>-<span class="hljs-number">26</span> <span class="hljs-number">2023</span>-<span class="hljs-number">11</span>-07 <span class="hljs-number">68</span> -<span class="hljs-number">12.313689</span> -<span class="hljs-number">11.760164</span> <span class="hljs-number">3</span> <span class="hljs-number">2024</span>-03-<span class="hljs-number">26</span> <span class="hljs-number">2024</span>-04-<span class="hljs-number">17</span> <span class="hljs-number">2024</span>-04-<span class="hljs-number">18</span> <span class="hljs-number">24</span> -<span class="hljs-number">9.736568</span> -<span class="hljs-number">8.365719</span> <span class="hljs-number">4</span> <span class="hljs-number">2023</span>-07-<span class="hljs-number">19</span> <span class="hljs-number">2023</span>-08-<span class="hljs-number">11</span> <span class="hljs-number">2023</span>-08-<span class="hljs-number">30</span> <span class="hljs-number">43</span> -<span class="hljs-number">8.844754</span> -<span class="hljs-number">7.638776</span> <span class="hljs-number">5</span> <span class="hljs-number">2023</span>-02-<span class="hljs-number">15</span> <span class="hljs-number">2023</span>-02-<span class="hljs-number">22</span> <span class="hljs-number">2023</span>-03-07 <span class="hljs-number">21</span> -<span class="hljs-number">6.694283</span> -<span class="hljs-number">6.039259</span>

Strategy Visualization</pre></div><figure id="c9d1"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*b2DjV_LWatQjyiGDqVzPZQ.png"><figcaption>Portfolio before MPO: Cumulative Returns vs Benchmark.</figcaption></figure><figure id="b32f"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*ZZTNAIxdIEnnSfE5KJ9Qxg.png"><figcaption>Portfolio before MPO: Cumulative Returns vs Benchmark (Volatility Matched).</figcaption></figure><figure id="0871"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*TlvUlYKZlBB8sbn1uPR_0A.png"><figcaption>Portfolio before MPO: EOY Returns vs Benchmark</figcaption></figure><figure id="10e0"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*KMedPMXqJnVnUkp0rg4WpQ.png"><figcaption>Portfolio before MPO: Distribution of Monthly Returns vs Daily Active Returns.</figcaption></figure><figure id="83bf"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*EQS4WSICnEFpeONZ_aO9Sw.png"><figcaption>Portfolio before MPO: 6-months rolling volatility and rolling beta to benchmark.</figcaption></figure><figure id="54ec"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*3PInj6HqgNQK-oRdT2GcSg.png"><figcaption>Portfolio before MPO: 6-months rolling Sharpe and Sortino ratios.</figcaption></figure><figure id="7a20"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*9bTQRukDDULxqpT25suyYg.png"><figcaption>Portfolio before MPO: Strategy-Worst 5 Drawdown Periods vs Underwater Plot</figcaption></figure><figure id="9b16"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*R_a_cSLVELtPEp2Ra6EyKw.png"><figcaption>Portfolio before MPO: Strategy-Monthly Active Returns (%)</figcaption></figure><figure id="c074"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*hFk8w1SvxxEzOIeo1tE5ww.png"><figcaption>Portfolio before MPO: Strategy-Return Quantiles</figcaption></figure><h2 id="b330">Quantstats Portfolio Report After MPO</h2><ul><li>Our updated portfolio after MPO consists of 4 tech stocks (option 2) with optimized weights, viz.</li></ul><div id="ae5d"><pre><span class="hljs-comment">#Optimized max Sharpe Ratio SciPy </span> weights = [<span class="hljs-number">0.06</span>, <span class="hljs-number">0.39</span>, <span class="hljs-number">0.01</span>, <span class="hljs-number">0.54</span>] <span class="hljs-comment"># Defining weights for each stock</span> portfolio = df[<span class="hljs-string">'NVDA'</span>]*weights[<span class="hljs-number">0</span>] + df[<span class="hljs-string">'AMD'</span>]*weights[<span class="hljs-number">1</span>] + df[<span class="hljs-string">'INTC'</span>]*weights[<span class="hljs-number">2</span>] + df[<span class="hljs-string">'MSI'</span>]*weights[<span class="hljs-number">3</span>] <span class="hljs-comment"># Creating portfolio multiplying each stock for its respective weight </span> portfolio <span class="hljs-comment"># Portfolio after MPO</span>

Date <span class="hljs-number">2022</span>-04-<span class="hljs-number">19</span> <span class="hljs-number">174.796358</span> <span class="hljs-number">2022</span>-04-<span class="hljs-number">20</span> <span class="hljs-number">174.686317</span> <span class="hljs-number">2022</span>-04-<span class="hljs-number">21</span> <span class="hljs-number">170.144846</span> <span class="hljs-number">2022</span>-04-<span class="hljs-number">22</span> <span class="hljs-number">164.859244</span> <span class="hljs-number">2022</span>-04-<span class="hljs-number">25</span> <span class="hljs-number">166.153715</span> ...
<span class="hljs-number">2024</span>-04-<span class="hljs-number">12</span> <span class="hljs-number">302.605097</span> <span class="hljs-number">2024</span>-04-<span class="hljs-number">15</span> <span class="hljs-number">297.321696</span> <span class="hljs-number">2024</span>-04-<span class="hljs-number">16</span> <span class="hljs-number">300.220396</span> <span class="hljs-number">2024</span>-04-<span class="hljs-number">17</span> <span class="hljs-number">294.721005</span> <span class="hljs-number">2024</span>-04-<span class="hljs-number">18</span> <span class="hljs-number">296.741143</span> Length: <span class="hljs-number">503</span>, dtype: float64</pre></div><ul><li>Plotting the optimized portfolio report vs ^GSPC benchmark</li></ul><div id="65a4"><pre>qs.reports.full(portfolio, benchmark = df[<span class="hljs-string">'^GSPC'</span>])

Performance Metrics

                       Benchmark    Strategy

Start Period <span class="hljs-number">2022</span>-04-<span class="hljs-number">20</span> <span class="hljs-number">2022</span>-04-<span class="hljs-number">20</span> End Period <span class="hljs-number">2024</span>-04-<span class="hljs-number">18</span> <span class="hljs-number">2024</span>-04-<span class="hljs-number">18</span> Risk-Free Rate <span class="hljs-number">0.0</span>% <span class="hljs-number">0.0</span>% Time <span class="hljs-keyword">in</span> Market <span class="hljs-number">100.0</span>% <span class="hljs-number">100.0</span>%

Cumulative Return <span class="hljs-number">13.12</span>% <span class="hljs-number">69.76</span>% CAGR﹪ <span class="hljs-number">4.35</span>% <span class="hljs-number">20.08</span>%

Sharpe <span class="hljs-number">0.43</span> <span class="hljs-number">1.14</span> Prob. Sharpe Ratio <span class="hljs-number">72.72</span>% <span class="hljs-number">94.8</span>% Smart Sharpe <span class="hljs-number">0.4</span> <span class="hljs-number">1.07</span> Sortino <span class="hljs-number">0.61</span> <span class="hljs-number">1.77</span> Smart Sortino <span class="hljs-number">0.58</span> <span class="hljs-number">1.66</span> Sortino/√<span class="hljs-number">2</span> <span class="hljs-number">0.43</span> <span class="hljs-number">1.25</span> Smart Sortino/√<span class="hljs-number">2</span> <span class="hljs-number">0.41</span> <span class="hljs-number">1.17</span> Omega <span class="hljs-number">1.22</span> <span class="hljs-number">1.22</span>

Max Drawdown -<span class="hljs-number">19.79</span>% -<span class="hljs-number">23.87</span>% Longest DD Days <span class="hljs-number">447</span> <span class="hljs-number">177</span> Volatility (ann.) <span class="hljs-number">18.32</span>% <span class="hljs-number">26.29</span>% R^<span class="hljs-number">2</span> <span class="hljs-number">0.66</span> <span class="hljs-number">0.66</span> Information Ratio <span class="hljs-number">0.09</span> <span class="hljs-number">0.09</span> Calmar <span class="hljs-number">0.22</span> <span class="hljs-number">0.84</span> Skew -<span class="hljs-number">0.11</span> <span class="hljs-number">0.28</span> Kurtosis <span class="hljs-number">2.03</span> <span class="hljs-number">1.91</span>

Expected Daily % <span class="hljs-number">0.02</span>% <span class="hljs-number">0.11</span>% Expected Monthly % <span class="hljs-number">0.49</span>% <span class="hljs-number">2.14</span>% Expected Yearly % <span class="hljs-number">4.2</span>% <span class="hljs-number">19.29</span>% Kelly Criterion <span class="hljs-number">1.14</span>% <span class="hljs-number">9.95</span>% Risk of Ruin <span class="hljs-number">0.0</span>% <span class="hljs-number">0.0</span>% Daily Value-at-Risk -<span class="hljs-number">1.87</span>% -<span class="hljs-number">2.61</span>% Expected Shortfall (cVaR) -<span class="hljs-number">1.87</span>% -<span class="hljs-number">2.61</span>%

Max Consecutive Wins <span class="hljs-number">8</span> <span class="hljs-number">8</span> Max Consecutive Losses <span class="hljs-number">6</span> <span class="hljs-number">7</span> Gain/Pain Ratio <span class="hljs-number">0.08</span> <span class="hljs-number">0.22</span> Gain/Pain (1M) <span class="hljs-number">0.31</span> <span class="hljs-number">1.1</span>

Payoff Ratio <span class="hljs-number">1.02</span> <span class="hljs-number">1.14</span> Profit Factor <span class="hljs-number">1.08</span> <span class="hljs-number">1.22</span> Common Sense Ratio <span class="hljs-number">1.24</span> <span class="hljs-number">1.56</span> CPC Index <span class="hljs-number">0.55</span> <span class="hljs-number">0.72</span> Tail Ratio <span class="hljs-number">1.15</span> <span class="hljs-number">1.28</span> Outlier Win Ratio <span class="hljs-number">4.23</span> <span class="hljs-number">2.88</span> Outlier Loss Ratio <span class="hljs-number">4.75</span> <span class="hljs-number">3.39</span>

MTD -<span class="hljs-number">3.93</span>% -<span class="hljs-number">6.31</span>% 3M <span class="hljs-number">6.51</span>% <span class="hljs-number">11.03</span>% 6M <span class="hljs-number">15.42</span>% <span class="hljs-number">32.87</span>% YTD <span class="hljs-number">5.83</span>% <span class="hljs-number">15.78</span>% 1Y <span class="hljs-number">21.59</span>% <span class="hljs-number">43.52</span>% 3Y (ann.) <span class="hljs-number">4.35</span>% <span class="hljs-number">20.08</span>% 5Y (ann.) <span class="hljs-number">4.35</span>% <span class="hljs-number">20.08</span>% 10Y (ann.) <span class="hljs-number">4.35</span>% <span class="hljs-number">20.08</span>% All-time (ann.) <span class="hljs-number">4.35</span>% <span class="hljs-number">20.08</span>%

Best Day <span class="hljs-number">5.54</span>% <span class="hljs-number">7.53</span>% Worst Day -<span class="hljs-number">4.32</span>% -<span class="hljs-number">5.35</span>% Best Month <span class="hljs-number">9.11</span>% <span class="hljs-number">17.09</span>% Worst Month -<span class="hljs-number">9.34</span>% -<span class="hljs-number">11.76</span>% Best Year <span class="hljs-number">24.23</span>% <span class="hljs-number">49.61</span>% Worst Year -<span class="hljs-number">13.96</span>% -<span class="hljs-number">2.0</span>%

Avg. Drawdown -<span class="hljs-number">2.28</span>% -<span class="hljs-number">3.14</span>% Avg. Drawdown Days <span class="hljs-number">30</span> <span class="hljs-number">19</span> Recovery Factor <span class="hljs-number">0.79</span> <span class="hljs-number">2.51</span> Ulcer Index <span class="hljs-number">0.09</span> <span class="hljs-number">0.07</span> Serenity Index <span class="hljs-number">0.13</span> <span class="hljs-number">1.13</span>

Avg. Up Month <span class="hljs-number">4.78</span>% <span class="hljs-number">8.58</span>% Avg. Down Month -<span class="hljs-number">5.73</span>% -<span class="hljs-number">6.69</span>% Win Days % <span class="hljs-number">50.2</span>% <span class="hljs-number">51.99</span>% Win Month % <span class="hljs-number">60.0</span>% <span class="hljs-number">60.0</span>% Win Quarter % <span class="hljs-number">55.56</span>% <span class="hljs-number">66.67</span>% Win Year % <span class="hljs-number">66.67</span>% <span class="hljs-number">66.67</span>%

Beta - <span class="hljs-number">1.16</span> Alpha - <span class="hljs-number">0.21</span> Correlation - <span class="hljs-number">80.94</span>% Treynor Ratio - <span class="hljs-number">60.06</span>% <span class="hljs-literal">None</span> Worst <span class="hljs-number">5</span> Drawdowns Start Valley End Days Max Drawdown <span class="hljs-number">99</span>% Max Drawdown <span class="hljs-number">1</span> <span class="hljs-number">2022</span>-08-<span class="hljs-number">17</span> <span class="hljs-number">2022</span>-<span class="hljs-number">10</span>-<span class="hljs-number">14</span> <span class="hljs-number">2023</span>-02-09 <span class="hljs-number">177</span> -<span class="hljs-number">23.867018</span> -<span class="hljs-number">20.927214</span> <span class="hljs-number">2</span> <span class="hljs-number">2022</span>-04-<span class="hljs-number">21</span> <span class="hljs-number">2022</span>-06-<span class="hljs-number">16</span> <span class="hljs-number">2022</span>-08-01 <span class="hljs-number">103</span> -<span class="hljs-number">16.555311</span> -<span class="hljs-number">14.846316</span> <span class="hljs-number">3</span> <span class="hljs-number">2023</span>-07-<span class="hljs-number">26</span> <span class="hljs-number">2023</span>-<span class="hljs-number">10</span>-<span class="hljs-number">27</span> <span class="hljs-number">2023</span>-<span class="hljs-number">11</span>-02 <span class="hljs-number">100</span> -<span class="hljs-number">9.848466</span> -<span class="hljs-number">9.803296</span> <span class="hljs-number">4</span> <span class="hljs-number">2024</span>-03-08 <span class="hljs-number">2024</span>-04-<span class="hljs-number">17</span> <span class="hljs-number">2024</span>-04-<span class="hljs-number">18</span> <span class="hljs-number">42</span> -<span class="hljs-number">7.452712</span> -<span class="hljs-number">6.818356</span> <span class="hljs-number">5</span> <span class="hljs-number">2023</span>-02-<span class="hljs-number">16</span> <span class="hljs-number">2023</span>-02-<span class="hljs-number">22</span> <span class="hljs-number">2023</span>-03-<span class="hljs-number">15</span> <span class="hljs-number">28</span> -<span class="hljs-number">4.578890</span> -<span class="hljs-number">4.128242</span> Strategy Visualization</pre></div><figure id="54a4"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*yBaKGeALdQf66vCXXR4Dhg.png"><figcaption>Portfolio after MPO: Cumulative Returns vs Benchmark.</figcaption></figure><figure id="071f"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*D-JctNSQjNVuu0-wagTQBA.png"><figcaption>Portfolio after MPO: Cumulative Returns vs Benchmark (Volatility Matched).</figcaption></figure><figure id="7ebd"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*AAKkaKTfYSXowQHAuSawKQ.png"><figcaption>Portfolio after MPO: EOY Returns vs Benchmark</figcaption></figure><figure id="9d46"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*DYnnnyWojXkdMcQqfwYcZQ.png"><figcaption>Portfolio after MPO: Distribution of Monthly Returns, Daily Active Returns, and Rolling Beta to Benchmark.</figcaption></figure><figure id="6d37"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*o8STkP15-_8R0m19h5BpAg.png"><figcaption>Portfolio after MPO: 6-months rolling volatility, Sharpe and Sortino ratios.</figcaption></figure><figure id="4015"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*fd2Da2dbTUA0B7RpO5vVFw.png"><figcaption>Portfolio after MPO: Strategy-Worst 5 Drawdown Periods vs Underwater Plot</figcaption></figure><figure id="6cff"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*1GoSIrWa5aAlDir4Haa4Ew.png"><figcaption>Portfolio after MPO: Strategy-Monthly Active Returns (%)</figcaption></figure><figure id="1cee"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*CPPKI_DIOwKjcX2aPc8fsg.png"><figcaption>Portfolio after MPO: Strategy-Return Quantiles</figcaption></figure><h2 id="871f">Conclusions</h2><ul><li>In this post, we have addressed the challenge of Financial Risk Management (FRM) for Automated Trading (AT) and Investments in Stocks.</li><li>We have implemented and tested state-of-the art FRM tools and techniques in stock AT and investments.</li><li>We have deployed a set of SaaS products to open and close trades according to set rules such as points of price movement in an underlying market. Once the current market conditions match any predetermined criteria, our trading algorithms (algos) can execute a buy or sell order on your behalf.</li><li>As a pilot project, we have used these products to perform robust backtesting, technical/fundamental financial analysis, and stochastic portfolio optimization of 4 tech game-changers (<a href="https://www.nvidia.com/en-us/">NVDA</a>, <a href="https://www.amd.com/en.html">AMD</a>, <a href="https://www.intel.com/content/www/us/en/homepage.html">INTC</a> & <a href="https://finance.yahoo.com/quote/MSI/">MSI</a>) vs <a href="https://finance.yahoo.com/quote/SPY/">S&P 500</a> benchmark.</li><li>Our interactive stock screening and portfolio optimization dashboard<b> </b>can quickly and easily see the asset’s health at a glance and identify areas that require attention. In addition, our fintech KPI visualizations can communicate the risks associated with specific investments.</li><li>Overall, we have looked at AT use-case examples based on best fintech industry practices that set to accelerate the AT market growth in the near future. Factors such as the increasing adoption of numerical optimization and stochastic simulation methods, real-time data analytics, interactive visualizations, and the rising demand for automated trading systems substantiate the great business value of our study.</li></ul><h2 id="b8a8">Explore More</h2><ul><li><a href="https://wp.me/pdMwZd-8ab">A Market-Neutral Strategy</a></li><li><a href="https://wp.me/pdMwZd-859">A Comprehensive Analysis of Best Trading Technical Indicators w/ TA-Lib — Tesla ‘23</a></li><li><a href="https://wp.me/pdMwZd-7A3">Plotly Dash TA Stock Market App</a></li><li><a href="https://wp.me/pdMwZd-7dS">Returns-Volatility Domain K-Means Clustering and LSTM Anomaly Detection of S&P 500 Stocks</a></li><li><a href="https://wp.me/pdMwZd-7dI">NVIDIA Returns-Drawdowns MVA & RNN Mean Reversal Trading</a></li><li><a href="https://wp.me/pdMwZd-7e5">Oracle Monte Carlo Stock Simulations</a></li><li><a href="https://wp.me/pdMwZd-7by">NVIDIA Rolling Volatility: GARCH & XGBoost</a></li><li><a href="https://wp.me/pdMwZd-71E">IQR-Based Log Price Volatility Ranking of Top 19 Blue Chips</a></li><li><a href="https://wp.me/pdMwZd-6V7">Multiple-Criteria Technical Analysis of Blue Chips in Python</a></li><li><a href="https://wp.me/pdMwZd-61w">Datapane Stock Screener App from Scratch</a></li><li><a href="https://wp.me/pdMwZd-58A">Data Visualization in Python — 1. Stock Technical Indicators</a></li><li><a href="https://wp.me/pdMwZd-50m">Top 6 Reliability/Risk Engineering Learnings</a></li><li><a href="https://wp.me/pdMwZd-4Vu">JPM Breakouts: Auto ARIMA, FFT, LSTM & Stock Indicators</a></li><li><a href="https://wp.me/pdMwZd-4Rj">Post-SVB Risk Aware Investing</a></li><li><a href="https://wp.me/pdMwZd-4TI">Applying a Risk-Aware Portfolio Rebalancing Strategy to ETF, Energy, Pharma, and Aerospace/Defense Stocks in 2023</a></li><li><a href="https://wp.me/pdMwZd-4Je">Portfolio Optimization of 20 Dividend Growth Stocks</a></li><li><a href="https://wp.me/pdMwZd-4Fd">Donchian Channel Trading Systems</a></li><li><a href="https://wp.me/pdMwZd-4IB">Towards Max(ROI/Risk) Trading</a></li><li><a href="https://wp.me/pdMwZd-1uP">The Qullamaggie’s TSLA Breakouts for Swing Traders</a></li><li><a href="https://wp.me/pdMwZd-192">Algorithmic Testing Stock Portfolios to Optimize the Risk/Reward Ratio</a></li><li><a href="https://wp.me/pdMwZd-Rm">Quant Trading using Monte Carlo Predictions and 62 AI-Assisted Trading Technical Indicators (TTI)</a></li><li><a href="https://wp.me/pdMwZd-50m">Top 6 Reliability/Risk Engineering Learnings</a></li><li><a href="https://wp.me/pdMwZd-1YB">Stock Portfolio Risk/Return Optimization</a></li><li><a href="https://wp.me/pdMwZd-1Zl">Risk/Return QC via Portfolio Optimization — Current Positions of The Dividend Breeder</a></li><li><a href="https://wp.me/pdMwZd-21T">Portfolio Optimization Risk/Return QC — Positions of Humble Div vs Dividend Glenn</a></li><li><a href="https://wp.me/pdMwZd-26M">Risk/Return POA — Dr. Dividend’s Positions</a></li><li><a href="https://wp.me/pdMwZd-Rp">Bear Market Similarity Analysis using Nasdaq 100 Index Data</a></li><li><a href="https://wp.me/pdMwZd-xC">Inflation-Resistant Stocks to Buy</a></li><li><a href="https://wp.me/pdMwZd-Q2">Basic Stock Price Analysis in Python</a></li><li><a href="https://wp.me/pdMwZd-Nv">Predicting Trend Reversal in Algorithmic Trading using Stochastic Oscillator in Python</a></li><li><a href="https://wp.me/pdMwZd-2f2">Bear vs. Bull Portfolio Risk/Return Optimization QC Analysis</a></li><li><a href="https://wp.me/pdMwZd-2Hd">The CodeX-Aroon Auto-Trading Approach — the AAPL Use Case</a></li><li><a href="https://wp.me/pdMwZd-2Ez">DJI Market State Analysis using the Cruz Fitting Algorithm</a></li><li><a href="https://wp.me/pdMwZd-5E7">Risk-Aware Strategies for DCA Investors</a></li><li><a href="https://wp.me/pdMwZd-2IJ">The $ASML Trading Strategies via the Plotly Stock Market Dashboard</a></li><li><a href="https://wp.me/pdMwZd-3Tq">Python Technical Analysis for BioTech — Get Buy Alerts on ABBV in 2023</a></li></ul><h2 id="cdab">Acknowledgements</h2><ul><li><a href="https://medium.com/@luuisotorres?source=user_profile-------------------------------------">Luís Fernando Torres</a></li><li><a href="https://github.com/bhavinmoriya/Bhavin-Moriya">BHAVIN MORIYA</a></li><li><a href="https://karthikramx.medium.com/?source=user_profile-------------------------------------">Karthik Ram</a></li><li><a href="https://mishraayush447.medium.com/?source=user_profile-------------------------------------">Ayush Mishra</a></li></ul><h2 id="3a6d">References</h2><ul><li><a href="https://www.kaggle.com/code/lusfernandotorres/data-science-for-financial-markets">Data Science for Financial Markets</a></li><li><a href="https://www.kaggle.com/code/bhavinmoriya/beta-of-a-stock-capm-from-scratch">Beta of a Stock & CAPM from Scratch</a></li><li><a href="https://blog.devgenius.io/algorithmic-trading-backtesting-a-strategy-in-python-3a136be16ece">Algorithmic Trading — Backtesting a strategy in python</a></li><li><a href="https://www.machinelearningplus.com/machine-learning/portfolio-optimization-python-example/">Portfolio Optimization with Python using Efficient Frontier with Practical Examples</a></li><li><a href="https://github.com/PyroQuant">PyroQuant</a>/<a href="https://github.com/PyroQuant/Portfolio-Optimizer">Portfolio-Optimizer</a></li><li><a href="https://mishraayush447.medium.com/portfolio-optimization-using-python-b8d2b64e520e">Portfolio optimization using Python</a></li><li><a href="https://www.mlq.ai/python-for-finance-portfolio-optimization/">Python for Finance: Portfolio Optimization</a></li><li><a href="https://towardsdatascience.com/historical-stock-price-data-in-python-a0b6dc826836">Historical Stock Price Data in Python</a></li><li><a href="https://plotly.com/python/v3/ipython-notebooks/markowitz-portfolio-optimization/">Markowitz Portfolio Optimization in Python/v3</a></li><li><a href="https://medium.datadriveninvestor.com/portfolio-optimization-with-python-using-scipy-optimize-monte-carlo-method-a5b4e89e0548">Portfolio Optimization with Python: using SciPy Optimize & Monte Carlo Method</a></li><li><a href="https://github.com/ranaroussi">ranaroussi</a>/<a href="https://github.com/ranaroussi/quantstats">quantstats</a></li></ul><p id="d351"><b>Relevant 3rd Party SaaS Platforms</b></p><ul><li><a href="https://wp.me/pdMwZd-8N">Macroaxis Wealth Optimization</a></li><li><a href="https://wp.me/pdMwZd-Po">Track All Markets with TradingView</a></li><li><a href="https://www.barchart.com/">Barchart</a></li></ul><h2 id="fe24">Stock Market Research Updates</h2><ul><li><a href="https://wp.me/pdMwZd-ch">A Weekday Market Research Update</a></li><li><a href="https://wp.me/pdMwZd-1D2">Towards min(Risk/Reward) — SeekingAlpha August Bear Market Update</a></li><li><a href="https://wp.me/pdMwZd-1Sp">All Eyes on ETFs Sep ‘22</a></li><li><a href="https://wp.me/pdMwZd-2oX">Zacks Investment Research Update Q4'22</a></li><li><a href="https://wp.me/pdMwZd-4gL">Stocks to Watch in 2023: MarketBeat Ideas</a></li></ul><h2 id="971e">Tutorials for Beginners</h2><ul><li><a href="https://wp.me/pdMwZd-8m">Upswing Resilient Investor Guide</a></li></ul><h2 id="e219">Contacts</h2><ul><li><a href="https://newdigitals.org/">Website</a></li><li><a href="https://github.com/alva922">GitHub</a></li><li><a href="https://twitter.com/alzapress">X/Twitter</a></li><li><a href="https://nl.pinterest.com/alexzap922/">Pinterest</a></li><li><a href="https://mastodon.social/@alexzap">Mastodon</a></li><li><a href="https://alva922.tumblr.com/">Tumblr</a></li></ul></article></body>

Backtesting Algo-Trading Strategies, FinTech Analysis & Portfolio Optimization: NVDA, AMD, INTC, MSI vs S&P 500 Benchmark

Image template by @ondostudios via Canva.

  • The objective of this project is to perform robust backtesting and portfolio optimization of 4 tech game-changers (NVDA, AMD, INTC & MSI) vs the S&P 500 benchmark.
  • Backtesting is a risk-free validation of (algo-)trading strategies, ensuring they are adaptable to various market conditions. The process of backtesting involves selecting relevant historical data, applying the technical analysis strategy, and then analyzing its potential profitability.
  • Portfolio Optimization (PO) aims at resolving the risk-return trade-off by maximizing the return for every additional unit of risk taken in the portfolio. PO utilizes advanced financial models to generate optimal investment portfolios balancing desired returns with acceptable risk levels. PO takes into account a variety of factors: market trends, asset correlations, technical indicators, etc.
  • What about the 4 top-rated tech stocks to be discussed in the sequel?
  • Chip companies have been in focus this year due to the massive opportunity created by the generative artificial intelligence ambitions of tech giants following the success of OpenAI’s ChatGPT.
  • Advanced Micro Devices (NASDAQ:AMD), Nvidia (NASDAQ:NVDA), and Intel (NASDAQ:INTC) are known to be the best chip stocks as per Wall Street experts.
  • Motorola Solutions, Inc. (NYSE: MSI) is the leading global provider of mission critical communication services. MSI serves more than 100,000 public safety and commercial customers across more than 100 countries. MSI recently announced the launch of cutting-edge solutions with advanced capabilities.
  • The present study entails a comprehensive fintech analysis of these 4 celebrated stocks in terms of their business performance and overall financial health over recent years.
  • Using the proposed set of Python open-source tools and techniques to analyze historical stock data and financial statements can help investors make more informed business decisions to predict and improve ROI.
  • Let’s get to the heart of the matter!

Basic Installations & Imports

  • Set up a Lean, Robust Data Science Environment with Miniconda and Conda-Forge. You can find the latest version of Miniconda here.
  • Go to C:\Users\miniconda3\condabin (in cmd)
  • Use the conda info --envs command to access a list of all available conda environments for your user profile.
  • Use the following command to create a new conda environment
  • conda create — name python==X.X.X
  • Use the activate command
  • conda activate <env_name>
  • Use the conda install -c conda-forge jupyter install the jupyter package.
  • Run jupyter notebook
  • Use deactivate command upon exiting
  • conda deactivate
  • Within the Jupyter Notebook IDE:
  • Setting up the working directory YOURPATH
import os
os.chdir('YOURPATH')    # Set working directory
os. getcwd() 
  • Installing and importing Python packages
!pip install yfinance, plotly, scipy, matplotlib, quantstats, ta, datetime, seaborn, pandas_ta 
!pip install pyfolio-reloaded 
import numpy as np
import pandas as pd
import yfinance as yf
import matplotlib.pyplot as plt
from scipy.optimize import minimize
from scipy.stats import norm
from scipy.stats import skew, kurtosis
from scipy.stats.mstats import gmean
import plotly.express as px
from plotly.subplots import make_subplots
import plotly.graph_objects as go
import quantstats as qs
import ta
from datetime import datetime as dt, timedelta as td
import seaborn as sns
import pandas_ta as taa
import pyfolio as pf

Reading Historical Stock Data

  • Defining the ticker list, fetching the historical data and printing first 5 rows of the data
tickers_list = ['NVDA', 'INTC', 'AMD', 'MSI']
start_date = '2023-01-01'

data0 = yf.download(tickers_list, start=start_date)
data0.tail()

Price Adj Close Close High ... Low Open Volume
Ticker AMD INTC MSI NVDA AMD INTC MSI NVDA AMD INTC ... MSI NVDA AMD INTC MSI NVDA AMD INTC MSI NVDA
Date                     
2024-04-15 160.320007 36.310001 338.579987 860.010010 160.320007 36.310001 338.579987 860.010010 164.440002 36.700001 ... 338.380005 859.289978 164.429993 36.040001 347.630005 890.979980 61461200 50751600 778000 44307700
2024-04-16 163.460007 36.259998 340.109985 874.150024 163.460007 36.259998 340.109985 874.150024 164.880005 36.509998 ... 338.220001 860.640015 162.279999 36.270000 339.940002 864.330017 55302100 30607500 530300 37045300
2024-04-17 154.020004 35.680000 340.510010 840.349976 154.020004 35.680000 340.510010 840.349976 164.449997 36.130001 ... 339.209991 839.500000 163.970001 36.099998 342.200012 883.400024 75909000 41173300 540400 49540000
2024-04-18 155.080002 35.040001 339.459991 846.710022 155.080002 35.040001 339.459991 846.710022 156.960007 35.660000 ... 337.320007 824.020020 155.509995 35.419998 341.779999 849.700012 52669800 42334400 493700 44726000
2024-04-19 146.639999 34.200001 339.649994 762.000000 146.639999 34.200001 339.649994 762.000000 154.250000 35.130001 ... 337.160004 756.059998 151.589996 35.130001 341.070007 831.500000 71232500 58968800 1393000 87190500
5 rows × 24 columns
  • Checking the dataset size
data0.shape

(326, 24)
  • Printing the MultiIndex list of column names
data0.columns
MultiIndex([('Adj Close',  'AMD'),
            ('Adj Close', 'INTC'),
            ('Adj Close',  'MSI'),
            ('Adj Close', 'NVDA'),
            (    'Close',  'AMD'),
            (    'Close', 'INTC'),
            (    'Close',  'MSI'),
            (    'Close', 'NVDA'),
            (     'High',  'AMD'),
            (     'High', 'INTC'),
            (     'High',  'MSI'),
            (     'High', 'NVDA'),
            (      'Low',  'AMD'),
            (      'Low', 'INTC'),
            (      'Low',  'MSI'),
            (      'Low', 'NVDA'),
            (     'Open',  'AMD'),
            (     'Open', 'INTC'),
            (     'Open',  'MSI'),
            (     'Open', 'NVDA'),
            (   'Volume',  'AMD'),
            (   'Volume', 'INTC'),
            (   'Volume',  'MSI'),
            (   'Volume', 'NVDA')],
           names=['Price', 'Ticker'])
  • Printing the dataset info
data0.info()

<class 'pandas.core.frame.DataFrame'>
DatetimeIndex: 326 entries, 2023-01-03 to 2024-04-19
Data columns (total 24 columns):
 #   Column             Non-Null Count  Dtype  
---  ------             --------------  -----  
 0   (Adj Close, AMD)   326 non-null    float64
 1   (Adj Close, INTC)  326 non-null    float64
 2   (Adj Close, MSI)   326 non-null    float64
 3   (Adj Close, NVDA)  326 non-null    float64
 4   (Close, AMD)       326 non-null    float64
 5   (Close, INTC)      326 non-null    float64
 6   (Close, MSI)       326 non-null    float64
 7   (Close, NVDA)      326 non-null    float64
 8   (High, AMD)        326 non-null    float64
 9   (High, INTC)       326 non-null    float64
 10  (High, MSI)        326 non-null    float64
 11  (High, NVDA)       326 non-null    float64
 12  (Low, AMD)         326 non-null    float64
 13  (Low, INTC)        326 non-null    float64
 14  (Low, MSI)         326 non-null    float64
 15  (Low, NVDA)        326 non-null    float64
 16  (Open, AMD)        326 non-null    float64
 17  (Open, INTC)       326 non-null    float64
 18  (Open, MSI)        326 non-null    float64
 19  (Open, NVDA)       326 non-null    float64
 20  (Volume, AMD)      326 non-null    int64  
 21  (Volume, INTC)     326 non-null    int64  
 22  (Volume, MSI)      326 non-null    int64  
 23  (Volume, NVDA)     326 non-null    int64  
dtypes: float64(20), int64(4)
memory usage: 63.7 KB
  • Counting the number of missing values across the entire DataFrame
data0. isnull().values.any()
False
  • Selecting only Adj Close price for further studies (optionally)
tickers_list = ['NVDA', 'INTC', 'AMD', 'MSI']
data = yf.download(tickers_list,'2023-1-1')['Adj Close']
print(data.tail())
Ticker             AMD       INTC         MSI        NVDA
Date                                                     
2024-04-12  163.279999  35.689999  343.809998  881.859985
2024-04-15  160.320007  36.310001  338.579987  860.010010
2024-04-16  163.460007  36.259998  340.109985  874.150024
2024-04-17  154.020004  35.680000  340.510010  840.349976
2024-04-18  154.850006  35.387299  340.859985  847.275024
# Plotting candlestick chart without indicators
from plotly.subplots import make_subplots
import plotly.graph_objects as go
start='2023-01-01'
# Downloading Apple Stocks
nvda = yf.download('NVDA', start = start)

fig = make_subplots(rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.05, row_heights = [0.7, 0.3])
fig.add_trace(go.Candlestick(x=nvda.index,
                             open=nvda['Open'],
                             high=nvda['High'],
                             low=nvda['Low'],
                             close=nvda['Adj Close'],
                             name='NVDA'),
              row=1, col=1)


# Plotting volume chart on the second row 
fig.add_trace(go.Bar(x=nvda.index,
                     y=nvda['Volume'],
                     name='Volume',
                     marker=dict(color='orange', opacity=1.0)),
              row=2, col=1)

# Plotting annotation
fig.add_annotation(text='NVDA',
                    font=dict(color='white', size=40),
                    xref='paper', yref='paper',
                    x=0.5, y=0.65,
                    showarrow=False,
                    opacity=0.2)

# Configuring layout
fig.update_layout(title='NVDA Candlestick Chart',
                  yaxis=dict(title='Price (USD)'),
                  height=1000,
                 template = 'plotly_dark')

# Configuring axes and subplots
fig.update_xaxes(rangeslider_visible=False, row=1, col=1)
fig.update_xaxes(rangeslider_visible=False, row=2, col=1)
fig.update_yaxes(title_text='Price (USD)', row=1, col=1)
fig.update_yaxes(title_text='Volume', row=2, col=1)

fig.show()
NVDA candlesticks vs volume
# Plotting candlestick chart without indicators
from plotly.subplots import make_subplots
import plotly.graph_objects as go
start='2023-01-01'
# Downloading Apple Stocks
nvda = yf.download('AMD', start = start)

fig = make_subplots(rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.05, row_heights = [0.7, 0.3])
fig.add_trace(go.Candlestick(x=nvda.index,
                             open=nvda['Open'],
                             high=nvda['High'],
                             low=nvda['Low'],
                             close=nvda['Adj Close'],
                             name='AMD'),
              row=1, col=1)


# Plotting volume chart on the second row 
fig.add_trace(go.Bar(x=nvda.index,
                     y=nvda['Volume'],
                     name='Volume',
                     marker=dict(color='orange', opacity=1.0)),
              row=2, col=1)

# Plotting annotation
fig.add_annotation(text='AMD',
                    font=dict(color='white', size=40),
                    xref='paper', yref='paper',
                    x=0.5, y=0.65,
                    showarrow=False,
                    opacity=0.2)

# Configuring layout
fig.update_layout(title='AMD Candlestick Chart',
                  yaxis=dict(title='Price (USD)'),
                  height=1000,
                 template = 'plotly_dark')

# Configuring axes and subplots
fig.update_xaxes(rangeslider_visible=False, row=1, col=1)
fig.update_xaxes(rangeslider_visible=False, row=2, col=1)
fig.update_yaxes(title_text='Price (USD)', row=1, col=1)
fig.update_yaxes(title_text='Volume', row=2, col=1)

fig.show()
AMD candlesticks vs volume
# Plotting candlestick chart without indicators
from plotly.subplots import make_subplots
import plotly.graph_objects as go
start='2023-01-01'
# Downloading Apple Stocks
nvda = yf.download('MSI', start = start)

fig = make_subplots(rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.05, row_heights = [0.7, 0.3])
fig.add_trace(go.Candlestick(x=nvda.index,
                             open=nvda['Open'],
                             high=nvda['High'],
                             low=nvda['Low'],
                             close=nvda['Adj Close'],
                             name='MSI'),
              row=1, col=1)


# Plotting volume chart on the second row 
fig.add_trace(go.Bar(x=nvda.index,
                     y=nvda['Volume'],
                     name='Volume',
                     marker=dict(color='orange', opacity=1.0)),
              row=2, col=1)

# Plotting annotation
fig.add_annotation(text='MSI',
                    font=dict(color='white', size=40),
                    xref='paper', yref='paper',
                    x=0.5, y=0.65,
                    showarrow=False,
                    opacity=0.2)

# Configuring layout
fig.update_layout(title='MSI Candlestick Chart',
                  yaxis=dict(title='Price (USD)'),
                  height=1000,
                 template = 'plotly_dark')

# Configuring axes and subplots
fig.update_xaxes(rangeslider_visible=False, row=1, col=1)
fig.update_xaxes(rangeslider_visible=False, row=2, col=1)
fig.update_yaxes(title_text='Price (USD)', row=1, col=1)
fig.update_yaxes(title_text='Volume', row=2, col=1)

fig.show()
MSI candlesticks vs volume
# Plotting candlestick chart without indicators
from plotly.subplots import make_subplots
import plotly.graph_objects as go
start='2023-01-01'
# Downloading Apple Stocks
nvda = yf.download('INTC', start = start)

fig = make_subplots(rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.05, row_heights = [0.7, 0.3])
fig.add_trace(go.Candlestick(x=nvda.index,
                             open=nvda['Open'],
                             high=nvda['High'],
                             low=nvda['Low'],
                             close=nvda['Adj Close'],
                             name='INTC'),
              row=1, col=1)


# Plotting volume chart on the second row 
fig.add_trace(go.Bar(x=nvda.index,
                     y=nvda['Volume'],
                     name='Volume',
                     marker=dict(color='orange', opacity=1.0)),
              row=2, col=1)

# Plotting annotation
fig.add_annotation(text='INTC',
                    font=dict(color='white', size=40),
                    xref='paper', yref='paper',
                    x=0.5, y=0.65,
                    showarrow=False,
                    opacity=0.2)

# Configuring layout
fig.update_layout(title='INTC Candlestick Chart',
                  yaxis=dict(title='Price (USD)'),
                  height=1000,
                 template = 'plotly_dark')

# Configuring axes and subplots
fig.update_xaxes(rangeslider_visible=False, row=1, col=1)
fig.update_xaxes(rangeslider_visible=False, row=2, col=1)
fig.update_yaxes(title_text='Price (USD)', row=1, col=1)
fig.update_yaxes(title_text='Volume', row=2, col=1)

fig.show()
INTC candlesticks vs volume

Descriptive Statistics

  • Calculating aggregating statistics of the above stock data
data0.describe().T
Aggregating statistics of raw stock data
  • We can also split the summary statistics by considering 2Y period as an example:
nvda = yf.Ticker("NVDA").history(period='2y')['Close']
amd= yf.Ticker("AMD").history(period='2y')['Close']
msi= yf.Ticker("MSI").history(period='2y')['Close']
intc=yf.Ticker("INTC").history(period='2y')['Close']

#NVDA

print(nvda.mean())
print(nvda.median())
print(nvda.min())
print(nvda.max())
print(nvda.std())
print(nvda.mode())
nvda.describe()

351.51937653861984
274.44195556640625
112.18624114990234
950.02001953125
215.39582337067006
0    131.661697
1    132.511063
2    495.196777
Name: Close, dtype: float64
count    503.000000
mean     351.519377
std      215.395823
min      112.186241
25%      169.834717
50%      274.441956
75%      465.303574
max      950.020020
Name: Close, dtype: float64

#AMD

print(amd.mean())
print(amd.median())
print(amd.min())
print(amd.max())
print(amd.std())
print(amd.mode())
amd.describe()

105.61481091326795
98.01000213623047
55.939998626708984
211.3800048828125
34.499407320143966
0      75.250000
1      76.769997
2      84.639999
3      86.989998
4      89.839996
5     106.589996
6     115.820000
7     117.930000
8     138.580002
9     174.229996
10    178.699997
Name: Close, dtype: float64
count    503.000000
mean     105.614811
std       34.499407
min       55.939999
25%       81.500000
50%       98.010002
75%      117.845001
max      211.380005
Name: Close, dtype: float64

#MSI

print(msi.mean())
print(msi.median())
print(msi.min())
print(msi.max())
print(msi.std())
print(msi.mode())
msi.describe()

271.0420894736561
274.6322021484375
192.705078125
354.9800109863281
39.35118718826124
0    221.097916
1    252.675888
2    281.137085
3    281.982330
4    327.413727
Name: Close, dtype: float64
count    503.000000
mean     271.042089
std       39.351187
min      192.705078
25%      244.888878
50%      274.632202
75%      291.911865
max      354.980011
Name: Close, dtype: float64

#INTC

print(intc.mean())
print(intc.median())
print(intc.min())
print(intc.max())
print(intc.std())
print(intc.mode())
intc.describe()

34.70531823478684
34.16352462768555
24.0722599029541
50.61164855957031
6.538710173950736
0    25.927670
1    27.992682
Name: Close, dtype: float64
count    503.000000
mean      34.705318
std        6.538710
min       24.072260
25%       28.975665
50%       34.163525
75%       39.978010
max       50.611649
Name: Close, dtype: float64

Stock Returns, Volatility & Correlations

  • Calculating stock returns, volatility and correlations
# Packages
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline

# Read Data
# Define the ticker list
import pandas as pd
tickers_list = ['NVDA', 'INTC', 'AMD', 'MSI']

# Fetch the data
import yfinance as yf
data = yf.download(tickers_list,'2023-1-1')['Adj Close']

# Print first 5 rows of the data
print(data.tail())
Ticker             AMD       INTC         MSI        NVDA
Date                                                     
2024-04-15  160.320007  36.310001  338.579987  860.010010
2024-04-16  163.460007  36.259998  340.109985  874.150024
2024-04-17  154.020004  35.680000  340.510010  840.349976
2024-04-18  155.080002  35.040001  339.459991  846.710022
2024-04-19  146.639999  34.200001  339.649994  762.000000
# Volatility of 4 stocks
data.pct_change().apply(lambda x: np.log(1+x)).std().apply(lambda x: x*np.sqrt(250)).plot(kind='bar')
Volatility of 4 stocks
  • Calculating covariance of log percentage change
# Log of percentage change cov
cov_matrix = data.pct_change().apply(lambda x: np.log(1+x)).cov()
cov_matrix

Ticker AMD    INTC     MSI      NVDA
Ticker    
AMD 0.000925 0.000308 0.000072 0.000628
INTC 0.000308 0.000623 0.000054 0.000181
MSI 0.000072 0.000054 0.000130 0.000051
NVDA 0.000628 0.000181 0.000051 0.000913
  • Calculating correlations of log percentage change
corr_matrix = data.pct_change().apply(lambda x: np.log(1+x)).corr()
corr_matrix

Ticker AMD     INTC     MSI     NVDA
Ticker    
AMD 1.000000 0.405428 0.207200 0.684001
INTC 0.405428 1.000000 0.189382 0.239388
MSI 0.207200 0.189382 1.000000 0.149202
NVDA 0.684001 0.239388 0.149202 1.000000
data['NVDA'].corr(data['AMD'])
0.9365483296876527
data['NVDA'].corr(data['MSI'])
0.9002879914460777
data['NVDA'].corr(data['INTC'])
0.73578743334689
  • Calculating annual std
# Volatility is given by the annual standard deviation. We multiply by 250 because there are 250 trading days/year.
ann_sd = data.pct_change().apply(lambda x: np.log(1+x)).std().apply(lambda x: x*np.sqrt(250))
ann_sd
Ticker
AMD     0.480784
INTC    0.394629
MSI     0.180365
NVDA    0.477675
dtype: float64
  • Calculating yearly returns
# Yearly returns for individual companies
ind_er = data.resample('YE').last().pct_change().mean()
ind_er
Ticker
AMD    -0.005224
INTC   -0.317408
MSI     0.087934
NVDA    0.538782
dtype: float64
  • Comparing yearly returns vs annual volatility
assets = pd.concat([ind_er, ann_sd], axis=1) # Creating a table for visualising returns and volatility of assets
assets.columns = ['Returns', 'Volatility']
assets

     Returns Volatility
Ticker  
AMD -0.005224 0.480784
INTC -0.317408 0.394629
MSI 0.087934 0.180365
NVDA 0.538782 0.477675

Stock Returns vs Benchmark

  • Adding the ^GSPC benchmark and calculating the 2Y stock returns by fetching the Adj Close price
import numpy as np # linear algebra
import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)
import matplotlib.pyplot as plt
import plotly.express as px
import pandas_datareader as web
from datetime import datetime as dt, timedelta as td
end = dt.today()
start = end - td(days=2*365)

stocks = ['NVDA', 'INTC', 'AMD', 'MSI','^GSPC']

# Fetch the data
import yfinance as yf
df = yf.download(stocks,start=start,end=end)['Adj Close']

px.line(df * 100 / df.iloc[0])
Normalized stock price
  • Calculating the daily percentage change
ret_port = df.pct_change()
px.line(ret_port)
Daily percentage change
  • Calculating the cumulative return
cumretport = (1 + ret_port).cumprod() - 1 
px.line(cumretport*100)
Cumulative return
df_return = np.log(df / df.shift())
(df_return.mean() * 12).plot.bar()
plt.title(f'Annual log return')
cov = df_return.cov() * 12
market_cov = cov.iloc[0,1]
var_market = cov.iloc[1,1]
beta = market_cov / var_market
print (beta)
0.7333758533237972
Mean annual log return

Stock Beta

  • Calculating the 2Y stock beta
def get_beta(stock):
    start=dt.today() - td(days=365*2)
    df = yf.download([stock, '^GSPC'],start=start)['Adj Close']
    df_return = np.log(df / df.shift())
    (df_return.mean() * 12).plot.bar(title="Annual Log Return")
    cov = df_return.cov() * 12
    market_cov = cov.iloc[0,1]
    var_market = cov.iloc[1,1]
    beta = market_cov / var_market
    print(f'Beta 2Y of {stock.upper()} is : {beta}')
    return beta

get_beta('AMD')
1.9991308370043679

get_beta('MSI')
0.8368949323588019

get_beta('NVDA')
2.115183761971741

get_beta('INTC')
1.281878079502145

Sharpe Ratio

def get_sharpe(stock):
    start=dt.today()-td(365*2)
    df = yf.download(stock,start=start)['Adj Close']

    ret = df.pct_change()

    ri = ret.mean()

    rf = (.025 / 365) # as we are making it daily. Since interest accrues on weekend we did 365

    sigma = ret.std()

    sr = (ri - rf) * 250 ** .5 / sigma # annualize the sharpe ratio

    print(f'Sharpe Ratio of {stock.upper()} is : {sr}')
    return sr

get_sharpe('AMD')
Sharpe Ratio of AMD is : 0.6789019155264734

get_sharpe('NVDA')
Sharpe Ratio of NVDA is : 1.477564006585132

get_sharpe('MSI')
Sharpe Ratio of MSI is : 0.9070020467720372

get_sharpe('INTC')
Sharpe Ratio of INTC is : -0.15157724728913474
# Calculating Sharpe ratio
print('\n')
print("Sharpe Ratio for ^GSPC: ", qs.stats.sharpe(df['^GSPC']).round(2))
print('\n')
print("Sharpe Ratio for NVDA: ", qs.stats.sharpe(df['NVDA']).round(2))
print('\n')
print("Sharpe Ratio for AMD: ", qs.stats.sharpe(df['AMD']).round(2))
print('\n')
print("Sharpe Ratio for INTC: ", qs.stats.sharpe(df['INTC']).round(2))
print('\n')
print("Sharpe Ratio for MSI: ", qs.stats.sharpe(df['MSI']).round(2))

Sharpe Ratio for ^GSPC:  0.43


Sharpe Ratio for NVDA:  1.52


Sharpe Ratio for AMD:  0.72


Sharpe Ratio for INTC:  -0.11


Sharpe Ratio for MSI:  0.98

Company Financial Performance

  • Fetching the NVDA current market cap, annual financials, and cashflow
ticker = yf.Ticker('NVDA')
current_market_cap = ticker.info['marketCap']
print(current_market_cap)
ticker.financials
2104474992640
2024-01-31 2023-01-31 2022-01-31 2021-01-31
Tax Effect Of Unusual Items 0.0 -284130000.0 0.0 0.0
Tax Rate For Calcs 0.12 0.21 0.019 0.017
Normalized EBITDA 35583000000.0 7340000000.0 11351000000.0 5691000000.0
Total Unusual Items 0.0 -1353000000.0 0.0 0.0
Total Unusual Items Excluding Goodwill 0.0 -1353000000.0 0.0 0.0
Net Income From Continuing Operation Net Minority Interest 29760000000.0 4368000000.0 9752000000.0 4332000000.0
Reconciled Depreciation 1508000000.0 1544000000.0 1174000000.0 1098000000.0
Reconciled Cost Of Revenue 16621000000.0 11618000000.0 9439000000.0 6279000000.0
EBITDA 35583000000.0 5987000000.0 11351000000.0 5691000000.0
EBIT 34075000000.0 4443000000.0 10177000000.0 4593000000.0
Net Interest Income 609000000.0 5000000.0 -207000000.0 -127000000.0
Interest Expense 257000000.0 262000000.0 236000000.0 184000000.0
Interest Income 866000000.0 267000000.0 29000000.0 57000000.0
Normalized Income 29760000000.0 5436870000.0 9752000000.0 4332000000.0
Net Income From Continuing And Discontinued Operation 29760000000.0 4368000000.0 9752000000.0 4332000000.0
Total Expenses 27950000000.0 21397000000.0 16873000000.0 12143000000.0
Total Operating Income As Reported 32972000000.0 4224000000.0 10041000000.0 4532000000.0
Diluted Average Shares 2494000000.0 2507000000.0 2535000000.0 2512000000.0
Basic Average Shares 2469000000.0 2487000000.0 2496000000.0 2468000000.0
Diluted EPS 11.93 1.74 3.85 1.725
Basic EPS 12.05 1.76 3.91 1.755
Diluted NI Availto Com Stockholders 29760000000.0 4368000000.0 9752000000.0 4332000000.0
Net Income Common Stockholders 29760000000.0 4368000000.0 9752000000.0 4332000000.0
Net Income 29760000000.0 4368000000.0 9752000000.0 4332000000.0
Net Income Including Noncontrolling Interests 29760000000.0 4368000000.0 9752000000.0 4332000000.0
Net Income Continuous Operations 29760000000.0 4368000000.0 9752000000.0 4332000000.0
Tax Provision 4058000000.0 -187000000.0 189000000.0 77000000.0
Pretax Income 33818000000.0 4181000000.0 9941000000.0 4409000000.0
Other Income Expense 237000000.0 -1401000000.0 107000000.0 4000000.0
Other Non Operating Income Expenses 237000000.0 -48000000.0 107000000.0 4000000.0
Special Income Charges 0.0 -1353000000.0 0.0 0.0
Restructuring And Mergern Acquisition 0.0 1353000000.0 0.0 0.0
Net Non Operating Interest Income Expense 609000000.0 5000000.0 -207000000.0 -127000000.0
Interest Expense Non Operating 257000000.0 262000000.0 236000000.0 184000000.0
Interest Income Non Operating 866000000.0 267000000.0 29000000.0 57000000.0
Operating Income 32972000000.0 5577000000.0 10041000000.0 4532000000.0
Operating Expense 11329000000.0 9779000000.0 7434000000.0 5864000000.0
Research And Development 8675000000.0 7339000000.0 5268000000.0 3924000000.0
Selling General And Administration 2654000000.0 2440000000.0 2166000000.0 1940000000.0
Gross Profit 44301000000.0 15356000000.0 17475000000.0 10396000000.0
Cost Of Revenue 16621000000.0 11618000000.0 9439000000.0 6279000000.0
Total Revenue 60922000000.0 26974000000.0 26914000000.0 16675000000.0
Operating Revenue 60922000000.0 26974000000.0 26914000000.0 16675000000.0
ticker.cashflow

2024-01-31 2023-01-31 2022-01-31 2021-01-31
Free Cash Flow 27021000000.0 3808000000.0 8132000000.0 4694000000.0
Repurchase Of Capital Stock -9533000000.0 -10039000000.0 0.0 0.0
Repayment Of Debt -1250000000.0 0.0 -1000000000.0 0.0
Issuance Of Debt 0.0 0.0 4977000000.0 4968000000.0
Capital Expenditure -1069000000.0 -1833000000.0 -976000000.0 -1128000000.0
Interest Paid Supplemental Data 252000000.0 254000000.0 246000000.0 138000000.0
Income Tax Paid Supplemental Data 6549000000.0 1404000000.0 396000000.0 249000000.0
End Cash Position 7280000000.0 3389000000.0 1990000000.0 847000000.0
Beginning Cash Position 3389000000.0 1990000000.0 847000000.0 10896000000.0
Changes In Cash 3891000000.0 1399000000.0 1143000000.0 -10049000000.0
Financing Cash Flow -13633000000.0 -11617000000.0 1865000000.0 3804000000.0
Cash Flow From Continuing Financing Activities -13633000000.0 -11617000000.0 1865000000.0 3804000000.0
Net Other Financing Charges -2858000000.0 -1535000000.0 -1994000000.0 -963000000.0
Proceeds From Stock Option Exercised 403000000.0 355000000.0 281000000.0 194000000.0
Cash Dividends Paid -395000000.0 -398000000.0 -399000000.0 -395000000.0
Common Stock Dividend Paid NaN -398000000.0 -399000000.0 -395000000.0
Net Common Stock Issuance -9533000000.0 -10039000000.0 0.0 0.0
Common Stock Payments -9533000000.0 -10039000000.0 0.0 0.0
Net Issuance Payments Of Debt -1250000000.0 0.0 3977000000.0 4968000000.0
Net Long Term Debt Issuance -1250000000.0 0.0 3977000000.0 4968000000.0
Long Term Debt Payments -1250000000.0 0.0 -1000000000.0 0.0
Long Term Debt Issuance 0.0 0.0 4977000000.0 4968000000.0
Investing Cash Flow -10566000000.0 7375000000.0 -9830000000.0 -19675000000.0
Cash Flow From Continuing Investing Activities -10566000000.0 7375000000.0 -9830000000.0 -19675000000.0
Net Investment Purchase And Sale -9414000000.0 9257000000.0 -8591000000.0 -10023000000.0
Sale Of Investment 9782000000.0 21231000000.0 16220000000.0 9319000000.0
Purchase Of Investment -19196000000.0 -11974000000.0 -24811000000.0 -19342000000.0
Net Business Purchase And Sale -83000000.0 -49000000.0 -263000000.0 -8524000000.0
Purchase Of Business -83000000.0 -49000000.0 -263000000.0 -8524000000.0
Net PPE Purchase And Sale -1069000000.0 -1833000000.0 -976000000.0 -1128000000.0
Purchase Of PPE -1069000000.0 -1833000000.0 -976000000.0 -1128000000.0
Capital Expenditure Reported NaN NaN NaN -1128000000.0
Operating Cash Flow 28090000000.0 5641000000.0 9108000000.0 5822000000.0
Cash Flow From Continuing Operating Activities 28090000000.0 5641000000.0 9108000000.0 5822000000.0
Change In Working Capital -3722000000.0 -2207000000.0 -3363000000.0 -703000000.0
Change In Other Working Capital NaN NaN NaN 163000000.0
Change In Other Current Liabilities 514000000.0 252000000.0 192000000.0 163000000.0
Change In Payables And Accrued Expense 3556000000.0 790000000.0 1149000000.0 602000000.0
Change In Accrued Expense 2025000000.0 1341000000.0 581000000.0 290000000.0
Change In Payable 1531000000.0 -551000000.0 568000000.0 312000000.0
Change In Account Payable 1531000000.0 -551000000.0 568000000.0 312000000.0
Change In Prepaid Assets -1522000000.0 -1517000000.0 -1715000000.0 -394000000.0
Change In Inventory -98000000.0 -2554000000.0 -774000000.0 -524000000.0
Change In Receivables -6172000000.0 822000000.0 -2215000000.0 -550000000.0
Changes In Account Receivables -6172000000.0 822000000.0 -2215000000.0 -550000000.0
Other Non Cash Items -278000000.0 1346000000.0 47000000.0 -20000000.0
Stock Based Compensation 3549000000.0 2709000000.0 2004000000.0 1397000000.0
Deferred Tax -2489000000.0 -2164000000.0 -406000000.0 -282000000.0
Deferred Income Tax -2489000000.0 -2164000000.0 -406000000.0 -282000000.0
Depreciation Amortization Depletion 1508000000.0 1544000000.0 1174000000.0 1098000000.0
Depreciation And Amortization 1508000000.0 1544000000.0 1174000000.0 1098000000.0
Operating Gains Losses -238000000.0 45000000.0 -100000000.0 NaN
Gain Loss On Investment Securities -238000000.0 45000000.0 -100000000.0 NaN
Net Income From Continuing Operations 29760000000.0 4368000000.0 9752000000.0 4332000000.0
  • Fetching the AMD current market cap, annual financials, and cashflow
ticker = yf.Ticker('AMD')
current_market_cap = ticker.info['marketCap']
print(current_market_cap)
ticker.financials
248319901696

2023-12-31 2022-12-31 2021-12-31 2020-12-31
Tax Effect Of Unusual Items 0.0 0.0 -978740.801308 -14580000.0
Tax Rate For Calcs 0.21 0.21 0.13982 0.27
Normalized EBITDA 4149000000.0 5534000000.0 4173000000.0 1730000000.0
Total Unusual Items 0.0 0.0 -7000000.0 -54000000.0
Total Unusual Items Excluding Goodwill 0.0 0.0 -7000000.0 -54000000.0
Net Income From Continuing Operation Net Minority Interest 854000000.0 1320000000.0 3162000000.0 2490000000.0
Reconciled Depreciation 3551000000.0 4262000000.0 463000000.0 354000000.0
Reconciled Cost Of Revenue 10538000000.0 10836000000.0 8042000000.0 5062000000.0
EBITDA 4149000000.0 5534000000.0 4166000000.0 1676000000.0
EBIT 598000000.0 1272000000.0 3703000000.0 1322000000.0
Net Interest Income 100000000.0 -23000000.0 -26000000.0 -39000000.0
Interest Expense 106000000.0 88000000.0 34000000.0 47000000.0
Interest Income 206000000.0 65000000.0 8000000.0 8000000.0
Normalized Income 854000000.0 1320000000.0 3168021259.198692 2529420000.0
Net Income From Continuing And Discontinued Operation 854000000.0 1320000000.0 3162000000.0 2490000000.0
Total Expenses 22279000000.0 22337000000.0 12786000000.0 8394000000.0
Total Operating Income As Reported 401000000.0 1264000000.0 3648000000.0 1369000000.0
Diluted Average Shares 1625000000.0 1571000000.0 1229000000.0 1207000000.0
Basic Average Shares 1614000000.0 1561000000.0 1213000000.0 1184000000.0
Diluted EPS 0.53 0.84 2.57 2.06
Basic EPS 0.53 0.85 2.61 2.1
Diluted NI Availto Com Stockholders 854000000.0 1320000000.0 3162000000.0 2491000000.0
Average Dilution Earnings NaN 0.0 0.0 1000000.0
Net Income Common Stockholders 854000000.0 1320000000.0 3162000000.0 2490000000.0
Net Income 854000000.0 1320000000.0 3162000000.0 2490000000.0
Net Income Including Noncontrolling Interests 854000000.0 1320000000.0 3162000000.0 2490000000.0
Net Income Continuous Operations 854000000.0 1320000000.0 3162000000.0 2490000000.0
Earnings From Equity Interest Net Of Tax 16000000.0 14000000.0 6000000.0 5000000.0
Tax Provision -346000000.0 -122000000.0 513000000.0 -1210000000.0
Pretax Income 492000000.0 1184000000.0 3669000000.0 1275000000.0
Other Income Expense -9000000.0 -57000000.0 47000000.0 -55000000.0
Other Non Operating Income Expenses -8000000.0 5000000.0 -2000000.0 -3000000.0
Special Income Charges 0.0 0.0 -7000000.0 -54000000.0
Other Special Charges NaN NaN 7000000.0 54000000.0
Earnings From Equity Interest -1000000.0 -62000000.0 56000000.0 2000000.0
Net Non Operating Interest Income Expense 100000000.0 -23000000.0 -26000000.0 -39000000.0
Interest Expense Non Operating 106000000.0 88000000.0 34000000.0 47000000.0
Interest Income Non Operating 206000000.0 65000000.0 8000000.0 8000000.0
Operating Income 401000000.0 1264000000.0 3648000000.0 1369000000.0
Operating Expense 10059000000.0 9339000000.0 4281000000.0 2978000000.0
Other Operating Expenses -34000000.0 -102000000.0 -12000000.0 NaN
Depreciation Amortization Depletion Income Statement 1869000000.0 2100000000.0 0.0 0.0
Depreciation And Amortization In Income Statement 1869000000.0 2100000000.0 0.0 0.0
Amortization 1869000000.0 2100000000.0 0.0 0.0
Amortization Of Intangibles Income Statement 1869000000.0 2100000000.0 0.0 0.0
Research And Development 5872000000.0 5005000000.0 2845000000.0 1983000000.0
Selling General And Administration 2352000000.0 2336000000.0 1448000000.0 995000000.0
Gross Profit 10460000000.0 10603000000.0 7929000000.0 4347000000.0
Cost Of Revenue 12220000000.0 12998000000.0 8505000000.0 5416000000.0
Total Revenue 22680000000.0 23601000000.0 16434000000.0 9763000000.0
Operating Revenue 22680000000.0 23601000000.0 16434000000.0 9763000000.0
ticker.cashflow

2023-12-31 2022-12-31 2021-12-31 2020-12-31
Free Cash Flow 1121000000.0 3115000000.0 3220000000.0 777000000.0
Repurchase Of Capital Stock -1412000000.0 -4108000000.0 -1999000000.0 -78000000.0
Repayment Of Debt 0.0 -312000000.0 0.0 -200000000.0
Issuance Of Debt 0.0 991000000.0 0.0 200000000.0
Capital Expenditure -546000000.0 -450000000.0 -301000000.0 -294000000.0
Interest Paid Supplemental Data 84000000.0 85000000.0 25000000.0 31000000.0
Income Tax Paid Supplemental Data 523000000.0 685000000.0 35000000.0 8000000.0
End Cash Position 3933000000.0 4835000000.0 2535000000.0 1595000000.0
Beginning Cash Position 4835000000.0 2535000000.0 1595000000.0 1470000000.0
Changes In Cash -902000000.0 2300000000.0 940000000.0 125000000.0
Financing Cash Flow -1146000000.0 -3264000000.0 -1895000000.0 6000000.0
Cash Flow From Continuing Financing Activities -1146000000.0 -3264000000.0 -1895000000.0 6000000.0
Net Other Financing Charges -2000000.0 -2000000.0 NaN -1000000.0
Proceeds From Stock Option Exercised 268000000.0 167000000.0 104000000.0 85000000.0
Net Common Stock Issuance -1412000000.0 -4108000000.0 -1999000000.0 -78000000.0
Common Stock Payments -1412000000.0 -4108000000.0 -1999000000.0 -78000000.0
Net Issuance Payments Of Debt 0.0 679000000.0 0.0 0.0
Net Short Term Debt Issuance NaN NaN 0.0 200000000.0
Short Term Debt Issuance NaN NaN 0.0 200000000.0
Net Long Term Debt Issuance 0.0 679000000.0 0.0 0.0
Long Term Debt Payments 0.0 -312000000.0 0.0 -200000000.0
Long Term Debt Issuance 0.0 991000000.0 0.0 200000000.0
Investing Cash Flow -1423000000.0 1999000000.0 -686000000.0 -952000000.0
Cash Flow From Continuing Investing Activities -1423000000.0 1999000000.0 -686000000.0 -952000000.0
Net Other Investing Changes -11000000.0 -16000000.0 -7000000.0 NaN
Net Investment Purchase And Sale -735000000.0 1643000000.0 -378000000.0 -658000000.0
Sale Of Investment 2987000000.0 4310000000.0 1678000000.0 192000000.0
Purchase Of Investment -3722000000.0 -2667000000.0 -2056000000.0 -850000000.0
Net Business Purchase And Sale -131000000.0 822000000.0 0.0 0.0
Sale Of Business 0.0 2366000000.0 0.0 0.0
Purchase Of Business -131000000.0 -1544000000.0 0.0 0.0
Net PPE Purchase And Sale -546000000.0 -450000000.0 -301000000.0 -294000000.0
Purchase Of PPE -546000000.0 -450000000.0 -301000000.0 -294000000.0
Operating Cash Flow 1667000000.0 3565000000.0 3521000000.0 1071000000.0
Cash Flow From Continuing Operating Activities 1667000000.0 3565000000.0 3521000000.0 1071000000.0
Change In Working Capital -3049000000.0 -1846000000.0 -774000000.0 -931000000.0
Change In Payables And Accrued Expense -740000000.0 1856000000.0 1334000000.0 -74000000.0
Change In Accrued Expense -221000000.0 546000000.0 526000000.0 574000000.0
Change In Payable -519000000.0 1310000000.0 808000000.0 -648000000.0
Change In Account Payable -419000000.0 931000000.0 801000000.0 -513000000.0
Change In Prepaid Assets -472000000.0 -1197000000.0 -920000000.0 -231000000.0
Change In Inventory -580000000.0 -1401000000.0 -556000000.0 -417000000.0
Change In Receivables -1257000000.0 -1104000000.0 -632000000.0 -209000000.0
Changes In Account Receivables -1250000000.0 -1091000000.0 -640000000.0 -219000000.0
Other Non Cash Items -64000000.0 175000000.0 -2000000.0 22000000.0
Stock Based Compensation 1384000000.0 1081000000.0 379000000.0 274000000.0
Asset Impairment Charge NaN NaN NaN 0.0
Deferred Tax -1019000000.0 -1505000000.0 308000000.0 -1223000000.0
Deferred Income Tax -1019000000.0 -1505000000.0 308000000.0 -1223000000.0
Depreciation Amortization Depletion 3551000000.0 4262000000.0 463000000.0 354000000.0
Depreciation And Amortization 3551000000.0 4262000000.0 463000000.0 354000000.0
Depreciation 3551000000.0 4262000000.0 463000000.0 354000000.0
Operating Gains Losses 10000000.0 78000000.0 -15000000.0 85000000.0
Earnings Losses From Equity Investments -1000000.0 62000000.0 -56000000.0 -2000000.0
Gain Loss On Investment Securities NaN 62000000.0 -56000000.0 -2000000.0
Gain Loss On Sale Of PPE 11000000.0 16000000.0 34000000.0 33000000.0
Net Income From Continuing Operations 854000000.0 1320000000.0 3162000000.0 2490000000.0
  • Fetching the MSI current market cap, annual financials, and cashflow
ticker = yf.Ticker('MSI')
current_market_cap = ticker.info['marketCap']
print(current_market_cap)
ticker.financials

56290332672

2023-12-31 2022-12-31 2021-12-31 2020-12-31
Tax Effect Of Unusual Items -20502000.0 -14014000.0 -17550000.0 -19740000.0
Tax Rate For Calcs 0.201 0.098 0.195 0.188
Normalized EBITDA 2853000000.0 2338000000.0 2295000000.0 1921000000.0
Total Unusual Items -102000000.0 -143000000.0 -90000000.0 -105000000.0
Total Unusual Items Excluding Goodwill -102000000.0 -143000000.0 -90000000.0 -105000000.0
Net Income From Continuing Operation Net Minority Interest 1709000000.0 1363000000.0 1245000000.0 949000000.0
Reconciled Depreciation 356000000.0 440000000.0 438000000.0 409000000.0
Reconciled Cost Of Revenue 4829000000.0 4700000000.0 3929000000.0 3612000000.0
EBITDA 2751000000.0 2195000000.0 2205000000.0 1816000000.0
EBIT 2395000000.0 1755000000.0 1767000000.0 1407000000.0
Net Interest Income -216000000.0 -226000000.0 -208000000.0 -220000000.0
Interest Expense 249000000.0 240000000.0 215000000.0 233000000.0
Interest Income 33000000.0 14000000.0 7000000.0 13000000.0
Normalized Income 1790498000.0 1491986000.0 1317450000.0 1034260000.0
Net Income From Continuing And Discontinued Operation 1709000000.0 1363000000.0 1245000000.0 949000000.0
Total Expenses 7520000000.0 7246000000.0 6331000000.0 5919000000.0
Total Operating Income As Reported 2294000000.0 1661000000.0 1667000000.0 1383000000.0
Diluted Average Shares NaN 171900000.0 173600000.0 174100000.0
Basic Average Shares NaN 167500000.0 169200000.0 170000000.0
Diluted EPS NaN 7.93 7.17 5.45
Basic EPS NaN 8.14 7.36 5.58
Diluted NI Availto Com Stockholders 1709000000.0 1363000000.0 1245000000.0 949000000.0
Net Income Common Stockholders 1709000000.0 1363000000.0 1245000000.0 949000000.0
Net Income 1709000000.0 1363000000.0 1245000000.0 949000000.0
Minority Interests -5000000.0 -4000000.0 -5000000.0 -4000000.0
Net Income Including Noncontrolling Interests 1714000000.0 1367000000.0 1250000000.0 953000000.0
Net Income Continuous Operations 1714000000.0 1367000000.0 1250000000.0 953000000.0
Tax Provision 432000000.0 148000000.0 302000000.0 221000000.0
Pretax Income 2146000000.0 1515000000.0 1552000000.0 1174000000.0
Other Income Expense -96000000.0 -125000000.0 -80000000.0 -101000000.0
Other Non Operating Income Expenses 6000000.0 123000000.0 5000000.0 1000000.0
Special Income Charges -82000000.0 -92000000.0 -70000000.0 -90000000.0
Gain On Sale Of Ppe NaN 0.0 0.0 50000000.0
Gain On Sale Of Business -24000000.0 0.0 0.0 NaN
Other Special Charges 4000000.0 14000000.0 21000000.0 65000000.0
Write Off 16000000.0 1000000.0 0.0 9000000.0
Impairment Of Capital Assets 9000000.0 36000000.0 10000000.0 0.0
Restructuring And Mergern Acquisition 29000000.0 41000000.0 39000000.0 66000000.0
Earnings From Equity Interest 0.0 18000000.0 5000000.0 3000000.0
Gain On Sale Of Security -20000000.0 -51000000.0 -20000000.0 -15000000.0
Net Non Operating Interest Income Expense -216000000.0 -226000000.0 -208000000.0 -220000000.0
Interest Expense Non Operating 249000000.0 240000000.0 215000000.0 233000000.0
Interest Income Non Operating 33000000.0 14000000.0 7000000.0 13000000.0
Operating Income 2458000000.0 1866000000.0 1840000000.0 1495000000.0
Operating Expense 2512000000.0 2363000000.0 2200000000.0 2113000000.0
Other Operating Expenses 15000000.0 NaN NaN NaN
Depreciation Amortization Depletion Income Statement 177000000.0 257000000.0 236000000.0 215000000.0
Depreciation And Amortization In Income Statement 177000000.0 257000000.0 236000000.0 215000000.0
Amortization 177000000.0 257000000.0 236000000.0 215000000.0
Amortization Of Intangibles Income Statement 177000000.0 257000000.0 236000000.0 215000000.0
Research And Development 858000000.0 779000000.0 734000000.0 686000000.0
Selling General And Administration 1462000000.0 1327000000.0 1230000000.0 1212000000.0
General And Administrative Expense 1462000000.0 1327000000.0 1230000000.0 1212000000.0
Other Gand A 1561000000.0 1450000000.0 1353000000.0 1293000000.0
Salaries And Wages -99000000.0 -123000000.0 -123000000.0 -81000000.0
Gross Profit 4970000000.0 4229000000.0 4040000000.0 3608000000.0
Cost Of Revenue 5008000000.0 4883000000.0 4131000000.0 3806000000.0
Total Revenue 9978000000.0 9112000000.0 8171000000.0 7414000000.0
Operating Revenue 9978000000.0 9112000000.0 8171000000.0 7414000000.0
ticker.cashflow

2023-12-31 2022-12-31 2021-12-31 2020-12-31
Free Cash Flow 1791000000.0 1567000000.0 1594000000.0 1396000000.0
Repurchase Of Capital Stock -804000000.0 -836000000.0 -528000000.0 -612000000.0
Repayment Of Debt -1000000.0 -285000000.0 -353000000.0 -1714000000.0
Issuance Of Debt 0.0 595000000.0 844000000.0 1692000000.0
Issuance Of Capital Stock 104000000.0 156000000.0 102000000.0 108000000.0
Capital Expenditure -253000000.0 -256000000.0 -243000000.0 -217000000.0
Interest Paid Supplemental Data 234000000.0 226000000.0 207000000.0 217000000.0
Income Tax Paid Supplemental Data 587000000.0 307000000.0 257000000.0 181000000.0
End Cash Position 1705000000.0 1325000000.0 1874000000.0 1254000000.0
Beginning Cash Position 1325000000.0 1874000000.0 1254000000.0 1001000000.0
Effect Of Exchange Rate Changes 45000000.0 -79000000.0 -46000000.0 43000000.0
Changes In Cash 335000000.0 -470000000.0 666000000.0 210000000.0
Financing Cash Flow -1295000000.0 -906000000.0 -429000000.0 -966000000.0
Cash Flow From Continuing Financing Activities -1295000000.0 -906000000.0 -429000000.0 -966000000.0
Net Other Financing Charges -5000000.0 -6000000.0 -12000000.0 -4000000.0
Cash Dividends Paid -589000000.0 -530000000.0 -482000000.0 -436000000.0
Common Stock Dividend Paid -589000000.0 -530000000.0 -482000000.0 -436000000.0
Net Common Stock Issuance -700000000.0 -680000000.0 -426000000.0 -504000000.0
Common Stock Payments -804000000.0 -836000000.0 -528000000.0 -612000000.0
Common Stock Issuance 104000000.0 156000000.0 102000000.0 108000000.0
Net Issuance Payments Of Debt -1000000.0 310000000.0 491000000.0 -22000000.0
Net Short Term Debt Issuance NaN 0.0 0.0 0.0
Short Term Debt Payments NaN 0.0 0.0 -800000000.0
Short Term Debt Issuance NaN 0.0 0.0 800000000.0
Net Long Term Debt Issuance -1000000.0 310000000.0 491000000.0 -22000000.0
Long Term Debt Payments -1000000.0 -285000000.0 -353000000.0 -914000000.0
Long Term Debt Issuance 0.0 595000000.0 844000000.0 892000000.0
Investing Cash Flow -414000000.0 -1387000000.0 -742000000.0 -437000000.0
Cash Flow From Continuing Investing Activities -414000000.0 -1387000000.0 -742000000.0 -437000000.0
Net Investment Purchase And Sale 19000000.0 46000000.0 16000000.0 11000000.0
Sale Of Investment 19000000.0 46000000.0 16000000.0 11000000.0
Net Business Purchase And Sale -180000000.0 -1177000000.0 -521000000.0 -287000000.0
Purchase Of Business -180000000.0 -1177000000.0 -521000000.0 -287000000.0
Net PPE Purchase And Sale 0.0 0.0 6000000.0 56000000.0
Sale Of PPE 0.0 0.0 6000000.0 56000000.0
Capital Expenditure Reported -253000000.0 -256000000.0 -243000000.0 -217000000.0
Operating Cash Flow 2044000000.0 1823000000.0 1837000000.0 1613000000.0
Cash Flow From Continuing Operating Activities 2044000000.0 1823000000.0 1837000000.0 1613000000.0
Change In Working Capital -276000000.0 -329000000.0 0.0 102000000.0
Change In Other Working Capital -70000000.0 -425000000.0 -92000000.0 -25000000.0
Change In Other Current Assets -82000000.0 -1000000.0 -205000000.0 167000000.0
Change In Payables And Accrued Expense -144000000.0 451000000.0 578000000.0 -116000000.0
Change In Payable -144000000.0 451000000.0 578000000.0 -116000000.0
Change In Account Payable -144000000.0 451000000.0 578000000.0 -116000000.0
Change In Inventory 200000000.0 -242000000.0 -284000000.0 -14000000.0
Change In Receivables -180000000.0 -112000000.0 3000000.0 90000000.0
Changes In Account Receivables -180000000.0 -112000000.0 3000000.0 90000000.0
Other Non Cash Items 38000000.0 23000000.0 3000000.0 -13000000.0
Stock Based Compensation 212000000.0 172000000.0 129000000.0 129000000.0
Asset Impairment Charge 0.0 147000000.0 0.0 NaN
Deferred Tax NaN NaN 34000000.0 -25000000.0
Deferred Income Tax NaN NaN 34000000.0 -25000000.0
Depreciation Amortization Depletion 356000000.0 440000000.0 438000000.0 409000000.0
Depreciation And Amortization 356000000.0 440000000.0 438000000.0 409000000.0
Operating Gains Losses NaN 3000000.0 17000000.0 58000000.0
Pension And Employee Benefit Expense NaN NaN 0.0 0.0
Gain Loss On Investment Securities NaN -3000000.0 -1000000.0 2000000.0
Net Income From Continuing Operations 1714000000.0 1367000000.0 1250000000.0 953000000.0
  • Fetching the INTC current market cap, annual financials, and cashflow
ticker = yf.Ticker('INTC')
current_market_cap = ticker.info['marketCap']
print(current_market_cap)
149054291968

ticker.financials

2023-12-31 2022-12-31 2021-12-31 2020-12-31
Tax Effect Of Unusual Items -20502000.0 -14014000.0 -17550000.0 -19740000.0
Tax Rate For Calcs 0.201 0.098 0.195 0.188
Normalized EBITDA 2853000000.0 2338000000.0 2295000000.0 1921000000.0
Total Unusual Items -102000000.0 -143000000.0 -90000000.0 -105000000.0
Total Unusual Items Excluding Goodwill -102000000.0 -143000000.0 -90000000.0 -105000000.0
Net Income From Continuing Operation Net Minority Interest 1709000000.0 1363000000.0 1245000000.0 949000000.0
Reconciled Depreciation 356000000.0 440000000.0 438000000.0 409000000.0
Reconciled Cost Of Revenue 4829000000.0 4700000000.0 3929000000.0 3612000000.0
EBITDA 2751000000.0 2195000000.0 2205000000.0 1816000000.0
EBIT 2395000000.0 1755000000.0 1767000000.0 1407000000.0
Net Interest Income -216000000.0 -226000000.0 -208000000.0 -220000000.0
Interest Expense 249000000.0 240000000.0 215000000.0 233000000.0
Interest Income 33000000.0 14000000.0 7000000.0 13000000.0
Normalized Income 1790498000.0 1491986000.0 1317450000.0 1034260000.0
Net Income From Continuing And Discontinued Operation 1709000000.0 1363000000.0 1245000000.0 949000000.0
Total Expenses 7520000000.0 7246000000.0 6331000000.0 5919000000.0
Total Operating Income As Reported 2294000000.0 1661000000.0 1667000000.0 1383000000.0
Diluted Average Shares NaN 171900000.0 173600000.0 174100000.0
Basic Average Shares NaN 167500000.0 169200000.0 170000000.0
Diluted EPS NaN 7.93 7.17 5.45
Basic EPS NaN 8.14 7.36 5.58
Diluted NI Availto Com Stockholders 1709000000.0 1363000000.0 1245000000.0 949000000.0
Net Income Common Stockholders 1709000000.0 1363000000.0 1245000000.0 949000000.0
Net Income 1709000000.0 1363000000.0 1245000000.0 949000000.0
Minority Interests -5000000.0 -4000000.0 -5000000.0 -4000000.0
Net Income Including Noncontrolling Interests 1714000000.0 1367000000.0 1250000000.0 953000000.0
Net Income Continuous Operations 1714000000.0 1367000000.0 1250000000.0 953000000.0
Tax Provision 432000000.0 148000000.0 302000000.0 221000000.0
Pretax Income 2146000000.0 1515000000.0 1552000000.0 1174000000.0
Other Income Expense -96000000.0 -125000000.0 -80000000.0 -101000000.0
Other Non Operating Income Expenses 6000000.0 123000000.0 5000000.0 1000000.0
Special Income Charges -82000000.0 -92000000.0 -70000000.0 -90000000.0
Gain On Sale Of Ppe NaN 0.0 0.0 50000000.0
Gain On Sale Of Business -24000000.0 0.0 0.0 NaN
Other Special Charges 4000000.0 14000000.0 21000000.0 65000000.0
Write Off 16000000.0 1000000.0 0.0 9000000.0
Impairment Of Capital Assets 9000000.0 36000000.0 10000000.0 0.0
Restructuring And Mergern Acquisition 29000000.0 41000000.0 39000000.0 66000000.0
Earnings From Equity Interest 0.0 18000000.0 5000000.0 3000000.0
Gain On Sale Of Security -20000000.0 -51000000.0 -20000000.0 -15000000.0
Net Non Operating Interest Income Expense -216000000.0 -226000000.0 -208000000.0 -220000000.0
Interest Expense Non Operating 249000000.0 240000000.0 215000000.0 233000000.0
Interest Income Non Operating 33000000.0 14000000.0 7000000.0 13000000.0
Operating Income 2458000000.0 1866000000.0 1840000000.0 1495000000.0
Operating Expense 2512000000.0 2363000000.0 2200000000.0 2113000000.0
Other Operating Expenses 15000000.0 NaN NaN NaN
Depreciation Amortization Depletion Income Statement 177000000.0 257000000.0 236000000.0 215000000.0
Depreciation And Amortization In Income Statement 177000000.0 257000000.0 236000000.0 215000000.0
Amortization 177000000.0 257000000.0 236000000.0 215000000.0
Amortization Of Intangibles Income Statement 177000000.0 257000000.0 236000000.0 215000000.0
Research And Development 858000000.0 779000000.0 734000000.0 686000000.0
Selling General And Administration 1462000000.0 1327000000.0 1230000000.0 1212000000.0
General And Administrative Expense 1462000000.0 1327000000.0 1230000000.0 1212000000.0
Other Gand A 1561000000.0 1450000000.0 1353000000.0 1293000000.0
Salaries And Wages -99000000.0 -123000000.0 -123000000.0 -81000000.0
Gross Profit 4970000000.0 4229000000.0 4040000000.0 3608000000.0
Cost Of Revenue 5008000000.0 4883000000.0 4131000000.0 3806000000.0
Total Revenue 9978000000.0 9112000000.0 8171000000.0 7414000000.0
Operating Revenue 9978000000.0 9112000000.0 8171000000.0 7414000000.0
ticker.cashflow

2023-12-31 2022-12-31 2021-12-31 2020-12-31
Free Cash Flow 1791000000.0 1567000000.0 1594000000.0 1396000000.0
Repurchase Of Capital Stock -804000000.0 -836000000.0 -528000000.0 -612000000.0
Repayment Of Debt -1000000.0 -285000000.0 -353000000.0 -1714000000.0
Issuance Of Debt 0.0 595000000.0 844000000.0 1692000000.0
Issuance Of Capital Stock 104000000.0 156000000.0 102000000.0 108000000.0
Capital Expenditure -253000000.0 -256000000.0 -243000000.0 -217000000.0
Interest Paid Supplemental Data 234000000.0 226000000.0 207000000.0 217000000.0
Income Tax Paid Supplemental Data 587000000.0 307000000.0 257000000.0 181000000.0
End Cash Position 1705000000.0 1325000000.0 1874000000.0 1254000000.0
Beginning Cash Position 1325000000.0 1874000000.0 1254000000.0 1001000000.0
Effect Of Exchange Rate Changes 45000000.0 -79000000.0 -46000000.0 43000000.0
Changes In Cash 335000000.0 -470000000.0 666000000.0 210000000.0
Financing Cash Flow -1295000000.0 -906000000.0 -429000000.0 -966000000.0
Cash Flow From Continuing Financing Activities -1295000000.0 -906000000.0 -429000000.0 -966000000.0
Net Other Financing Charges -5000000.0 -6000000.0 -12000000.0 -4000000.0
Cash Dividends Paid -589000000.0 -530000000.0 -482000000.0 -436000000.0
Common Stock Dividend Paid -589000000.0 -530000000.0 -482000000.0 -436000000.0
Net Common Stock Issuance -700000000.0 -680000000.0 -426000000.0 -504000000.0
Common Stock Payments -804000000.0 -836000000.0 -528000000.0 -612000000.0
Common Stock Issuance 104000000.0 156000000.0 102000000.0 108000000.0
Net Issuance Payments Of Debt -1000000.0 310000000.0 491000000.0 -22000000.0
Net Short Term Debt Issuance NaN 0.0 0.0 0.0
Short Term Debt Payments NaN 0.0 0.0 -800000000.0
Short Term Debt Issuance NaN 0.0 0.0 800000000.0
Net Long Term Debt Issuance -1000000.0 310000000.0 491000000.0 -22000000.0
Long Term Debt Payments -1000000.0 -285000000.0 -353000000.0 -914000000.0
Long Term Debt Issuance 0.0 595000000.0 844000000.0 892000000.0
Investing Cash Flow -414000000.0 -1387000000.0 -742000000.0 -437000000.0
Cash Flow From Continuing Investing Activities -414000000.0 -1387000000.0 -742000000.0 -437000000.0
Net Investment Purchase And Sale 19000000.0 46000000.0 16000000.0 11000000.0
Sale Of Investment 19000000.0 46000000.0 16000000.0 11000000.0
Net Business Purchase And Sale -180000000.0 -1177000000.0 -521000000.0 -287000000.0
Purchase Of Business -180000000.0 -1177000000.0 -521000000.0 -287000000.0
Net PPE Purchase And Sale 0.0 0.0 6000000.0 56000000.0
Sale Of PPE 0.0 0.0 6000000.0 56000000.0
Capital Expenditure Reported -253000000.0 -256000000.0 -243000000.0 -217000000.0
Operating Cash Flow 2044000000.0 1823000000.0 1837000000.0 1613000000.0
Cash Flow From Continuing Operating Activities 2044000000.0 1823000000.0 1837000000.0 1613000000.0
Change In Working Capital -276000000.0 -329000000.0 0.0 102000000.0
Change In Other Working Capital -70000000.0 -425000000.0 -92000000.0 -25000000.0
Change In Other Current Assets -82000000.0 -1000000.0 -205000000.0 167000000.0
Change In Payables And Accrued Expense -144000000.0 451000000.0 578000000.0 -116000000.0
Change In Payable -144000000.0 451000000.0 578000000.0 -116000000.0
Change In Account Payable -144000000.0 451000000.0 578000000.0 -116000000.0
Change In Inventory 200000000.0 -242000000.0 -284000000.0 -14000000.0
Change In Receivables -180000000.0 -112000000.0 3000000.0 90000000.0
Changes In Account Receivables -180000000.0 -112000000.0 3000000.0 90000000.0
Other Non Cash Items 38000000.0 23000000.0 3000000.0 -13000000.0
Stock Based Compensation 212000000.0 172000000.0 129000000.0 129000000.0
Asset Impairment Charge 0.0 147000000.0 0.0 NaN
Deferred Tax NaN NaN 34000000.0 -25000000.0
Deferred Income Tax NaN NaN 34000000.0 -25000000.0
Depreciation Amortization Depletion 356000000.0 440000000.0 438000000.0 409000000.0
Depreciation And Amortization 356000000.0 440000000.0 438000000.0 409000000.0
Operating Gains Losses NaN 3000000.0 17000000.0 58000000.0
Pension And Employee Benefit Expense NaN NaN 0.0 0.0
Gain Loss On Investment Securities NaN -3000000.0 -1000000.0 2000000.0
Net Income From Continuing Operations 1714000000.0 1367000000.0 1250000000.0 953000000.0

Stock Fundamentals

  • Extracting the top 3 stock fundamentals: EPS, P/E, and ROE
# Getting  NVDA data
nvda1 = yf.Ticker("NVDA")
nvda_eps = nvda1.info['trailingEps']
nvda_pe_ratio = nvda1.info['trailingPE']
nvda_roe = nvda1.info['returnOnEquity']*100
print(nvda_eps)
print(nvda_pe_ratio)
print(nvda_roe)
print(nvda1.info) #Print general company info

11.96
63.712376
91.458

# Getting  AMD data
nvda1 = yf.Ticker("AMD")
nvda_eps = nvda1.info['trailingEps']
nvda_pe_ratio = nvda1.info['trailingPE']
nvda_roe = nvda1.info['returnOnEquity']*100
print(nvda1.info) #Print general company info
0.53
276.67926
1.544

# Getting  INTC data
nvda1 = yf.Ticker("INTC")
nvda_eps = nvda1.info['trailingEps']
nvda_pe_ratio = nvda1.info['trailingPE']
nvda_roe = nvda1.info['returnOnEquity']*100
print(nvda_eps)
print(nvda_pe_ratio)
print(nvda_roe)
print(nvda1.info) #Print general company info
0.4
85.5
1.5709999999999997

# Getting  MSI data
nvda1 = yf.Ticker("MSI")
nvda_eps = nvda1.info['trailingEps']
nvda_pe_ratio = nvda1.info['trailingPE']
nvda_roe = nvda1.info['returnOnEquity']*100
print(nvda_eps)
print(nvda_pe_ratio)
print(nvda_roe)
print(nvda1.info) #Print general company info
9.92
34.23891
394.02301
  • Checking debtToEquity, revenuePerShare, pegRatio, and revenueGrowth
#AMD

nvda1 = yf.Ticker("AMD")
nv_rev_growth = nvda1.info['revenueGrowth']
nv_debt_equity = nvda1.info['debtToEquity']
nv_rev_share = nvda1.info['revenuePerShare']
nv_peg_ratio = nvda1.info['pegRatio']
print(nv_rev_growth)
print(nv_debt_equity)
print(nv_rev_share)
print(nv_peg_ratio)
0.102
5.563
14.052
1.94

#INTC

nvda1 = yf.Ticker("INTC")
nv_rev_growth = nvda1.info['revenueGrowth']
nv_debt_equity = nvda1.info['debtToEquity']
nv_rev_share = nvda1.info['revenuePerShare']
nv_peg_ratio = nvda1.info['pegRatio']
print(nv_rev_growth)
print(nv_debt_equity)
print(nv_rev_share)
print(nv_peg_ratio)
0.097
45.226
12.942
0.69

#MSI

nvda1 = yf.Ticker("MSI")
nv_rev_growth = nvda1.info['revenueGrowth']
nv_debt_equity = nvda1.info['debtToEquity']
nv_rev_share = nvda1.info['revenuePerShare']
nv_peg_ratio = nvda1.info['pegRatio']
print(nv_rev_growth)
print(nv_debt_equity)
print(nv_rev_share)
print(nv_peg_ratio)
0.052
886.333
59.749
2.86

#NVDA

nvda1 = yf.Ticker("NVDA")
nv_rev_growth = nvda1.info['revenueGrowth']
nv_debt_equity = nvda1.info['debtToEquity']
nv_rev_share = nvda1.info['revenuePerShare']
nv_peg_ratio = nvda1.info['pegRatio']
print(nv_rev_growth)
print(nv_debt_equity)
print(nv_rev_share)
print(nv_peg_ratio)

2.653
25.725
24.675
1.03

Stock Kurtosis, Skewness & STD

  • Adding the S&P 500 benchmark and considering the 2Y portfolio
# Financial data 
import quantstats as qs
import ta
import yfinance as yf

stocks = ['NVDA', 'INTC', 'AMD', 'MSI','^GSPC']

# Fetch the data
import yfinance as yf

start=dt.today()-td(365*2)
df = yf.download(stocks,start=start)['Adj Close']

print('\n')
print("NVDA kurtosis: ", qs.stats.kurtosis(df.NVDA).round(2))
print('\n')
print("INTC kurtosis: ", qs.stats.kurtosis(df.INTC).round(2))
print('\n')
print("AMD kurtosis: ", qs.stats.kurtosis(df.AMD).round(2))
print('\n')
print("MSI kurtosis: ", qs.stats.kurtosis(df.MSI).round(2))
print('\n')
print("^GSPC kurtosis: ", qs.stats.kurtosis(df['^GSPC']).round(2))

NVDA kurtosis:  6.15


INTC kurtosis:  2.26


AMD kurtosis:  1.92


MSI kurtosis:  3.09


^GSPC kurtosis:  2.04
# Measuring skewness with quantstats
print('\n')
print("NVDA skewness: ", qs.stats.skew(df.NVDA).round(2))
print('\n')
print("INTC skewness: ", qs.stats.skew(df.INTC).round(2))
print('\n')
print("AMD skewness: ", qs.stats.skew(df.AMD).round(2))
print('\n')
print("MSI skewness: ", qs.stats.skew(df.MSI).round(2))
print('\n')
print("^GSPC skewness: ", qs.stats.skew(df['^GSPC']).round(2))

NVDA skewness:  1.0


INTC skewness:  -0.06


AMD skewness:  0.28


MSI skewness:  0.45


^GSPC skewness:  -0.11
# Calculating Standard Deviations
print('\n')
print("NVDA std: ", (df.NVDA.std()))
print('\n')
print("INTC std: ", (df.INTC.std()))
print('\n')
print("AMD std: ", (df.AMD.std()))
print('\n')
print("MSI std: ", (df.MSI.std()))
print('\n')
print("^GSPC std: ", (df['^GSPC'].std()))

NVDA std:  214.74791733336204


INTC std:  6.555661385679709


AMD std:  34.45680060452505


MSI std:  39.28116730667171


^GSPC std:  404.1021748731829

Stock Correlation Analysis

  • Displaying the seaborn pairplot of the aforementioned DataFrame df
import seaborn as sns
sns.pairplot(df, kind = 'reg')
plt.show()
Stock pairplot vs benchmark
  • Plotting the stock correlation matrix
# Correlation Matrix
corr = df.corr()
mask = np.zeros_like(corr)
mask[np.triu_indices_from(mask)] = True
sns.heatmap(corr, annot=True, mask = mask)
plt.show()
Stock correlation matrix

Key Technical Indicators

  • Adding Technical Indicators (TI) to gain more insights into the supply and demand of our securities.
  • NVDA candlesticks with key TI
start='2023-01-01'
# Downloading Stocks
nvda = yf.download('NVDA', start = start)

# Adding Moving Averages
nvda['EMA9'] = nvda['Adj Close'].ewm(span = 9, adjust = False).mean() # Exponential 9-Period Moving Average
nvda['SMA20'] = nvda['Adj Close'].rolling(window=20).mean() # Simple 20-Period Moving Average
nvda['SMA50'] = nvda['Adj Close'].rolling(window=50).mean() # Simple 50-Period Moving Average
nvda['SMA100'] = nvda['Adj Close'].rolling(window=100).mean() # Simple 100-Period Moving Average
nvda['SMA200'] = nvda['Adj Close'].rolling(window=200).mean() # Simple 200-Period Moving Average

# Adding RSI for 14-periods 
delta = nvda['Adj Close'].diff() # Calculating delta
gain = delta.where(delta > 0,0) # Obtaining gain values
loss = -delta.where(delta < 0,0) # Obtaining loss values
avg_gain = gain.rolling(window=14).mean() # Measuring the 14-period average gain value
avg_loss = loss.rolling(window=14).mean() # Measuring the 14-period average loss value
rs = avg_gain/avg_loss # Calculating the RS
nvda['RSI'] = 100 - (100 / (1 + rs)) # Creating an RSI column to the Data Frame 

# Adding Bollinger Bands 20-periods
nvda['BB_UPPER'] = nvda['SMA20'] + 2*nvda['Adj Close'].rolling(window=20).std() # Upper Band
nvda['BB_LOWER'] = nvda['SMA20'] - 2*nvda['Adj Close'].rolling(window=20).std() # Lower Band

# Adding ATR 14-periods
nvda['TR'] = pd.DataFrame(np.maximum(np.maximum(nvda['High'] - nvda['Low'], abs(nvda['High'] - nvda['Adj Close'].shift())), abs(nvda['Low'] - nvda['Adj Close'].shift())), index = nvda.index)
nvda['ATR'] = nvda['TR'].rolling(window = 14).mean() # Creating an ART column to the Data Frame 

# Plotting Candlestick charts with indicators
fig = make_subplots(rows=4, cols=1, shared_xaxes=True, vertical_spacing=0.05,row_heights=[0.6, 0.10, 0.10, 0.20])

# Candlestick 
fig.add_trace(go.Candlestick(x=nvda.index,
                             open=nvda['Open'],
                             high=nvda['High'],
                             low=nvda['Low'],
                             close=nvda['Adj Close'],
                             name='NVDA'),
              row=1, col=1)

# Moving Averages
fig.add_trace(go.Scatter(x=nvda.index,
                         y=nvda['EMA9'],
                         mode='lines',
                         line=dict(color='#90EE90'),
                         name='EMA9'),
              row=1, col=1)

fig.add_trace(go.Scatter(x=nvda.index,
                         y=nvda['SMA20'],
                         mode='lines',
                         line=dict(color='yellow'),
                         name='SMA20'),
              row=1, col=1)

fig.add_trace(go.Scatter(x=nvda.index,
                         y=nvda['SMA50'],
                         mode='lines',
                         line=dict(color='orange'),
                         name='SMA50'),
              row=1, col=1)

fig.add_trace(go.Scatter(x=nvda.index,
                         y=nvda['SMA100'],
                         mode='lines',
                         line=dict(color='purple'),
                         name='SMA100'),
              row=1, col=1)

fig.add_trace(go.Scatter(x=nvda.index,
                         y=nvda['SMA200'],
                         mode='lines',
                         line=dict(color='red'),
                         name='SMA200'),
              row=1, col=1)

# Bollinger Bands
fig.add_trace(go.Scatter(x=nvda.index,
                         y=nvda['BB_UPPER'],
                         mode='lines',
                         line=dict(color='#00BFFF'),
                         name='Upper Band'),
              row=1, col=1)

fig.add_trace(go.Scatter(x=nvda.index,
                         y=nvda['BB_LOWER'],
                         mode='lines',
                         line=dict(color='#00BFFF'),
                         name='Lower Band'),
              row=1, col=1)

fig.add_annotation(text='NVDA',
                    font=dict(color='white', size=40),
                    xref='paper', yref='paper',
                    x=0.5, y=0.65,
                    showarrow=False,
                    opacity=0.2)


# Relative Strengh Index (RSI)
fig.add_trace(go.Scatter(x=nvda.index,
                         y=nvda['RSI'],
                         mode='lines',
                         line=dict(color='#CBC3E3'),
                         name='RSI'),
              row=2, col=1)

# Adding marking lines at 70 and 30 levels
fig.add_shape(type="line",
              x0=nvda.index[0], y0=70, x1=nvda.index[-1], y1=70,
              line=dict(color="red", width=2, dash="dot"),
              row=2, col=1)
fig.add_shape(type="line",
              x0=nvda.index[0], y0=30, x1=nvda.index[-1], y1=30,
              line=dict(color="#90EE90", width=2, dash="dot"),
              row=2, col=1)

# Average True Range (ATR)
fig.add_trace(go.Scatter(x=nvda.index,
                         y=nvda['ATR'],
                         mode='lines',
                         line=dict(color='#00BFFF'),
                         name='ATR'),
              row=3, col=1)


# Volume
fig.add_trace(go.Bar(x=nvda.index,
                     y=nvda['Volume'],
                     name='Volume',
                     marker=dict(color='orange', opacity=1.0)),
              row=4, col=1)


# Layout
fig.update_layout(title='NVDA Candlestick Chart',
                  yaxis=dict(title='Price (USD)'),
                  height=1000,
                 template = 'plotly_dark')

# Axes and subplots
fig.update_xaxes(rangeslider_visible=False, row=1, col=1)
fig.update_xaxes(rangeslider_visible=False, row=4, col=1)
fig.update_yaxes(title_text='Price (USD)', row=1, col=1)
fig.update_yaxes(title_text='RSI', row=2, col=1)
fig.update_yaxes(title_text='ATR', row=3, col=1)
fig.update_yaxes(title_text='Volume', row=4, col=1)

fig.show()
NVDA candlesticks with key TI
  • AMD candlesticks with key TI
start='2023-01-01'
# Downloading Stocks
nvda = yf.download('AMD', start = start)
# Adding Moving Averages
nvda['EMA9'] = nvda['Adj Close'].ewm(span = 9, adjust = False).mean() # Exponential 9-Period Moving Average
nvda['SMA20'] = nvda['Adj Close'].rolling(window=20).mean() # Simple 20-Period Moving Average
nvda['SMA50'] = nvda['Adj Close'].rolling(window=50).mean() # Simple 50-Period Moving Average
nvda['SMA100'] = nvda['Adj Close'].rolling(window=100).mean() # Simple 100-Period Moving Average
nvda['SMA200'] = nvda['Adj Close'].rolling(window=200).mean() # Simple 200-Period Moving Average

# Adding RSI for 14-periods 
delta = nvda['Adj Close'].diff() # Calculating delta
gain = delta.where(delta > 0,0) # Obtaining gain values
loss = -delta.where(delta < 0,0) # Obtaining loss values
avg_gain = gain.rolling(window=14).mean() # Measuring the 14-period average gain value
avg_loss = loss.rolling(window=14).mean() # Measuring the 14-period average loss value
rs = avg_gain/avg_loss # Calculating the RS
nvda['RSI'] = 100 - (100 / (1 + rs)) # Creating an RSI column to the Data Frame 

# Adding Bollinger Bands 20-periods
nvda['BB_UPPER'] = nvda['SMA20'] + 2*nvda['Adj Close'].rolling(window=20).std() # Upper Band
nvda['BB_LOWER'] = nvda['SMA20'] - 2*nvda['Adj Close'].rolling(window=20).std() # Lower Band

# Adding ATR 14-periods
nvda['TR'] = pd.DataFrame(np.maximum(np.maximum(nvda['High'] - nvda['Low'], abs(nvda['High'] - nvda['Adj Close'].shift())), abs(nvda['Low'] - nvda['Adj Close'].shift())), index = nvda.index)
nvda['ATR'] = nvda['TR'].rolling(window = 14).mean() # Creating an ART column to the Data Frame 

# Plotting Candlestick charts with indicators
fig = make_subplots(rows=4, cols=1, shared_xaxes=True, vertical_spacing=0.05,row_heights=[0.6, 0.10, 0.10, 0.20])

# Candlestick 
fig.add_trace(go.Candlestick(x=nvda.index,
                             open=nvda['Open'],
                             high=nvda['High'],
                             low=nvda['Low'],
                             close=nvda['Adj Close'],
                             name='AMD'),
              row=1, col=1)

# Moving Averages
fig.add_trace(go.Scatter(x=nvda.index,
                         y=nvda['EMA9'],
                         mode='lines',
                         line=dict(color='#90EE90'),
                         name='EMA9'),
              row=1, col=1)

fig.add_trace(go.Scatter(x=nvda.index,
                         y=nvda['SMA20'],
                         mode='lines',
                         line=dict(color='yellow'),
                         name='SMA20'),
              row=1, col=1)

fig.add_trace(go.Scatter(x=nvda.index,
                         y=nvda['SMA50'],
                         mode='lines',
                         line=dict(color='orange'),
                         name='SMA50'),
              row=1, col=1)

fig.add_trace(go.Scatter(x=nvda.index,
                         y=nvda['SMA100'],
                         mode='lines',
                         line=dict(color='purple'),
                         name='SMA100'),
              row=1, col=1)

fig.add_trace(go.Scatter(x=nvda.index,
                         y=nvda['SMA200'],
                         mode='lines',
                         line=dict(color='red'),
                         name='SMA200'),
              row=1, col=1)

# Bollinger Bands
fig.add_trace(go.Scatter(x=nvda.index,
                         y=nvda['BB_UPPER'],
                         mode='lines',
                         line=dict(color='#00BFFF'),
                         name='Upper Band'),
              row=1, col=1)

fig.add_trace(go.Scatter(x=nvda.index,
                         y=nvda['BB_LOWER'],
                         mode='lines',
                         line=dict(color='#00BFFF'),
                         name='Lower Band'),
              row=1, col=1)

fig.add_annotation(text='AMD',
                    font=dict(color='white', size=40),
                    xref='paper', yref='paper',
                    x=0.5, y=0.65,
                    showarrow=False,
                    opacity=0.2)


# Relative Strengh Index (RSI)
fig.add_trace(go.Scatter(x=nvda.index,
                         y=nvda['RSI'],
                         mode='lines',
                         line=dict(color='#CBC3E3'),
                         name='RSI'),
              row=2, col=1)

# Adding marking lines at 70 and 30 levels
fig.add_shape(type="line",
              x0=nvda.index[0], y0=70, x1=nvda.index[-1], y1=70,
              line=dict(color="red", width=2, dash="dot"),
              row=2, col=1)
fig.add_shape(type="line",
              x0=nvda.index[0], y0=30, x1=nvda.index[-1], y1=30,
              line=dict(color="#90EE90", width=2, dash="dot"),
              row=2, col=1)

# Average True Range (ATR)
fig.add_trace(go.Scatter(x=nvda.index,
                         y=nvda['ATR'],
                         mode='lines',
                         line=dict(color='#00BFFF'),
                         name='ATR'),
              row=3, col=1)


# Volume
fig.add_trace(go.Bar(x=nvda.index,
                     y=nvda['Volume'],
                     name='Volume',
                     marker=dict(color='orange', opacity=1.0)),
              row=4, col=1)


# Layout
fig.update_layout(title='AMD Candlestick Chart',
                  yaxis=dict(title='Price (USD)'),
                  height=1000,
                 template = 'plotly_dark')

# Axes and subplots
fig.update_xaxes(rangeslider_visible=False, row=1, col=1)
fig.update_xaxes(rangeslider_visible=False, row=4, col=1)
fig.update_yaxes(title_text='Price (USD)', row=1, col=1)
fig.update_yaxes(title_text='RSI', row=2, col=1)
fig.update_yaxes(title_text='ATR', row=3, col=1)
fig.update_yaxes(title_text='Volume', row=4, col=1)

fig.show()
AMD candlesticks with key TI
  • MSI candlesticks with key TI
start='2023-01-01'
# Downloading Stocks
nvda = yf.download('MSI', start = start)
# Adding Moving Averages
nvda['EMA9'] = nvda['Adj Close'].ewm(span = 9, adjust = False).mean() # Exponential 9-Period Moving Average
nvda['SMA20'] = nvda['Adj Close'].rolling(window=20).mean() # Simple 20-Period Moving Average
nvda['SMA50'] = nvda['Adj Close'].rolling(window=50).mean() # Simple 50-Period Moving Average
nvda['SMA100'] = nvda['Adj Close'].rolling(window=100).mean() # Simple 100-Period Moving Average
nvda['SMA200'] = nvda['Adj Close'].rolling(window=200).mean() # Simple 200-Period Moving Average

# Adding RSI for 14-periods 
delta = nvda['Adj Close'].diff() # Calculating delta
gain = delta.where(delta > 0,0) # Obtaining gain values
loss = -delta.where(delta < 0,0) # Obtaining loss values
avg_gain = gain.rolling(window=14).mean() # Measuring the 14-period average gain value
avg_loss = loss.rolling(window=14).mean() # Measuring the 14-period average loss value
rs = avg_gain/avg_loss # Calculating the RS
nvda['RSI'] = 100 - (100 / (1 + rs)) # Creating an RSI column to the Data Frame 

# Adding Bollinger Bands 20-periods
nvda['BB_UPPER'] = nvda['SMA20'] + 2*nvda['Adj Close'].rolling(window=20).std() # Upper Band
nvda['BB_LOWER'] = nvda['SMA20'] - 2*nvda['Adj Close'].rolling(window=20).std() # Lower Band

# Adding ATR 14-periods
nvda['TR'] = pd.DataFrame(np.maximum(np.maximum(nvda['High'] - nvda['Low'], abs(nvda['High'] - nvda['Adj Close'].shift())), abs(nvda['Low'] - nvda['Adj Close'].shift())), index = nvda.index)
nvda['ATR'] = nvda['TR'].rolling(window = 14).mean() # Creating an ART column to the Data Frame 

# Plotting Candlestick charts with indicators
fig = make_subplots(rows=4, cols=1, shared_xaxes=True, vertical_spacing=0.05,row_heights=[0.6, 0.10, 0.10, 0.20])

# Candlestick 
fig.add_trace(go.Candlestick(x=nvda.index,
                             open=nvda['Open'],
                             high=nvda['High'],
                             low=nvda['Low'],
                             close=nvda['Adj Close'],
                             name='MSI'),
              row=1, col=1)

# Moving Averages
fig.add_trace(go.Scatter(x=nvda.index,
                         y=nvda['EMA9'],
                         mode='lines',
                         line=dict(color='#90EE90'),
                         name='EMA9'),
              row=1, col=1)

fig.add_trace(go.Scatter(x=nvda.index,
                         y=nvda['SMA20'],
                         mode='lines',
                         line=dict(color='yellow'),
                         name='SMA20'),
              row=1, col=1)

fig.add_trace(go.Scatter(x=nvda.index,
                         y=nvda['SMA50'],
                         mode='lines',
                         line=dict(color='orange'),
                         name='SMA50'),
              row=1, col=1)

fig.add_trace(go.Scatter(x=nvda.index,
                         y=nvda['SMA100'],
                         mode='lines',
                         line=dict(color='purple'),
                         name='SMA100'),
              row=1, col=1)

fig.add_trace(go.Scatter(x=nvda.index,
                         y=nvda['SMA200'],
                         mode='lines',
                         line=dict(color='red'),
                         name='SMA200'),
              row=1, col=1)

# Bollinger Bands
fig.add_trace(go.Scatter(x=nvda.index,
                         y=nvda['BB_UPPER'],
                         mode='lines',
                         line=dict(color='#00BFFF'),
                         name='Upper Band'),
              row=1, col=1)

fig.add_trace(go.Scatter(x=nvda.index,
                         y=nvda['BB_LOWER'],
                         mode='lines',
                         line=dict(color='#00BFFF'),
                         name='Lower Band'),
              row=1, col=1)

fig.add_annotation(text='MSI',
                    font=dict(color='white', size=40),
                    xref='paper', yref='paper',
                    x=0.5, y=0.65,
                    showarrow=False,
                    opacity=0.2)


# Relative Strengh Index (RSI)
fig.add_trace(go.Scatter(x=nvda.index,
                         y=nvda['RSI'],
                         mode='lines',
                         line=dict(color='#CBC3E3'),
                         name='RSI'),
              row=2, col=1)

# Adding marking lines at 70 and 30 levels
fig.add_shape(type="line",
              x0=nvda.index[0], y0=70, x1=nvda.index[-1], y1=70,
              line=dict(color="red", width=2, dash="dot"),
              row=2, col=1)
fig.add_shape(type="line",
              x0=nvda.index[0], y0=30, x1=nvda.index[-1], y1=30,
              line=dict(color="#90EE90", width=2, dash="dot"),
              row=2, col=1)

# Average True Range (ATR)
fig.add_trace(go.Scatter(x=nvda.index,
                         y=nvda['ATR'],
                         mode='lines',
                         line=dict(color='#00BFFF'),
                         name='ATR'),
              row=3, col=1)


# Volume
fig.add_trace(go.Bar(x=nvda.index,
                     y=nvda['Volume'],
                     name='Volume',
                     marker=dict(color='orange', opacity=1.0)),
              row=4, col=1)


# Layout
fig.update_layout(title='MSI Candlestick Chart',
                  yaxis=dict(title='Price (USD)'),
                  height=1000,
                 template = 'plotly_dark')

# Axes and subplots
fig.update_xaxes(rangeslider_visible=False, row=1, col=1)
fig.update_xaxes(rangeslider_visible=False, row=4, col=1)
fig.update_yaxes(title_text='Price (USD)', row=1, col=1)
fig.update_yaxes(title_text='RSI', row=2, col=1)
fig.update_yaxes(title_text='ATR', row=3, col=1)
fig.update_yaxes(title_text='Volume', row=4, col=1)
MSI candlesticks with key TI
  • INTC candlesticks with key TI
start='2023-01-01'
# Downloading Stocks
nvda = yf.download('INTC', start = start)
# Adding Moving Averages
nvda['EMA9'] = nvda['Adj Close'].ewm(span = 9, adjust = False).mean() # Exponential 9-Period Moving Average
nvda['SMA20'] = nvda['Adj Close'].rolling(window=20).mean() # Simple 20-Period Moving Average
nvda['SMA50'] = nvda['Adj Close'].rolling(window=50).mean() # Simple 50-Period Moving Average
nvda['SMA100'] = nvda['Adj Close'].rolling(window=100).mean() # Simple 100-Period Moving Average
nvda['SMA200'] = nvda['Adj Close'].rolling(window=200).mean() # Simple 200-Period Moving Average

# Adding RSI for 14-periods 
delta = nvda['Adj Close'].diff() # Calculating delta
gain = delta.where(delta > 0,0) # Obtaining gain values
loss = -delta.where(delta < 0,0) # Obtaining loss values
avg_gain = gain.rolling(window=14).mean() # Measuring the 14-period average gain value
avg_loss = loss.rolling(window=14).mean() # Measuring the 14-period average loss value
rs = avg_gain/avg_loss # Calculating the RS
nvda['RSI'] = 100 - (100 / (1 + rs)) # Creating an RSI column to the Data Frame 

# Adding Bollinger Bands 20-periods
nvda['BB_UPPER'] = nvda['SMA20'] + 2*nvda['Adj Close'].rolling(window=20).std() # Upper Band
nvda['BB_LOWER'] = nvda['SMA20'] - 2*nvda['Adj Close'].rolling(window=20).std() # Lower Band

# Adding ATR 14-periods
nvda['TR'] = pd.DataFrame(np.maximum(np.maximum(nvda['High'] - nvda['Low'], abs(nvda['High'] - nvda['Adj Close'].shift())), abs(nvda['Low'] - nvda['Adj Close'].shift())), index = nvda.index)
nvda['ATR'] = nvda['TR'].rolling(window = 14).mean() # Creating an ART column to the Data Frame 

# Plotting Candlestick charts with indicators
fig = make_subplots(rows=4, cols=1, shared_xaxes=True, vertical_spacing=0.05,row_heights=[0.6, 0.10, 0.10, 0.20])

# Candlestick 
fig.add_trace(go.Candlestick(x=nvda.index,
                             open=nvda['Open'],
                             high=nvda['High'],
                             low=nvda['Low'],
                             close=nvda['Adj Close'],
                             name='INTC'),
              row=1, col=1)

# Moving Averages
fig.add_trace(go.Scatter(x=nvda.index,
                         y=nvda['EMA9'],
                         mode='lines',
                         line=dict(color='#90EE90'),
                         name='EMA9'),
              row=1, col=1)

fig.add_trace(go.Scatter(x=nvda.index,
                         y=nvda['SMA20'],
                         mode='lines',
                         line=dict(color='yellow'),
                         name='SMA20'),
              row=1, col=1)

fig.add_trace(go.Scatter(x=nvda.index,
                         y=nvda['SMA50'],
                         mode='lines',
                         line=dict(color='orange'),
                         name='SMA50'),
              row=1, col=1)

fig.add_trace(go.Scatter(x=nvda.index,
                         y=nvda['SMA100'],
                         mode='lines',
                         line=dict(color='purple'),
                         name='SMA100'),
              row=1, col=1)

fig.add_trace(go.Scatter(x=nvda.index,
                         y=nvda['SMA200'],
                         mode='lines',
                         line=dict(color='red'),
                         name='SMA200'),
              row=1, col=1)

# Bollinger Bands
fig.add_trace(go.Scatter(x=nvda.index,
                         y=nvda['BB_UPPER'],
                         mode='lines',
                         line=dict(color='#00BFFF'),
                         name='Upper Band'),
              row=1, col=1)

fig.add_trace(go.Scatter(x=nvda.index,
                         y=nvda['BB_LOWER'],
                         mode='lines',
                         line=dict(color='#00BFFF'),
                         name='Lower Band'),
              row=1, col=1)

fig.add_annotation(text='INTC',
                    font=dict(color='white', size=40),
                    xref='paper', yref='paper',
                    x=0.5, y=0.65,
                    showarrow=False,
                    opacity=0.2)


# Relative Strengh Index (RSI)
fig.add_trace(go.Scatter(x=nvda.index,
                         y=nvda['RSI'],
                         mode='lines',
                         line=dict(color='#CBC3E3'),
                         name='RSI'),
              row=2, col=1)

# Adding marking lines at 70 and 30 levels
fig.add_shape(type="line",
              x0=nvda.index[0], y0=70, x1=nvda.index[-1], y1=70,
              line=dict(color="red", width=2, dash="dot"),
              row=2, col=1)
fig.add_shape(type="line",
              x0=nvda.index[0], y0=30, x1=nvda.index[-1], y1=30,
              line=dict(color="#90EE90", width=2, dash="dot"),
              row=2, col=1)

# Average True Range (ATR)
fig.add_trace(go.Scatter(x=nvda.index,
                         y=nvda['ATR'],
                         mode='lines',
                         line=dict(color='#00BFFF'),
                         name='ATR'),
              row=3, col=1)


# Volume
fig.add_trace(go.Bar(x=nvda.index,
                     y=nvda['Volume'],
                     name='Volume',
                     marker=dict(color='orange', opacity=1.0)),
              row=4, col=1)


# Layout
fig.update_layout(title='INTC Candlestick Chart',
                  yaxis=dict(title='Price (USD)'),
                  height=1000,
                 template = 'plotly_dark')

# Axes and subplots
fig.update_xaxes(rangeslider_visible=False, row=1, col=1)
fig.update_xaxes(rangeslider_visible=False, row=4, col=1)
fig.update_yaxes(title_text='Price (USD)', row=1, col=1)
fig.update_yaxes(title_text='RSI', row=2, col=1)
fig.update_yaxes(title_text='ATR', row=3, col=1)
fig.update_yaxes(title_text='Volume', row=4, col=1)

INTC candlesticks with key TI

Backtesting INTC Trading Strategies

  • The above INTC candlesticks with key TI suggest that we need to outperform the passive buy-and-hold strategy of this stock. In doing so, we will implement and backtest the following TI-based trading strategies
# Importing necessary libraries
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import yfinance as yf
import pyfolio as pf
import datetime as dt

import os
import warnings

# print all outputs
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"

# downloading historical necessary data for backtesting and analysis
_start = dt.date(2022,1,2)
_end = dt.date(2024,4,20)
ticker = 'INTC'
df = yf.download(ticker, start = _start, end = _end)
#df.tail()

# calculating buy and hold strategy returns
df['bnh_returns'] = np.log(df['Adj Close']/df['Adj Close'].shift(1))

# creating bollinger band indicators
df['ma20'] = df['Adj Close'].rolling(window=20).mean()
df['std'] = df['Adj Close'].rolling(window=20).std()
df['upper_band'] = df['ma20'] + (2 * df['std'])
df['lower_band'] = df['ma20'] - (2 * df['std'])
df.drop(['Open','High','Low'],axis=1,inplace=True,errors='ignore')
#df.tail(5)

# BUY condition
df['signal'] = np.where((df['Adj Close'] < df['lower_band']) &
                        (df['Adj Close'].shift(1) >=       df['lower_band']),1,0)

# SELL condition
df['signal'] = np.where( (df['Adj Close'] > df['upper_band']) &
                          (df['Adj Close'].shift(1) <= df['upper_band']),-1,df['signal'])
# creating long and short positions 
df['position'] = df['signal'].replace(to_replace=0, method='ffill')

# shifting by 1, to account of close price return calculations
df['position'] = df['position'].shift(1)

# calculating stretegy returns
df['strategy_returns'] = df['bnh_returns'] * (df['position'])

#df.tail(5)

# comparing buy & hold strategy / bollinger bands strategy returns
print("Buy and hold returns:",df['bnh_returns'].cumsum()[-1])
print("Strategy returns:",df['strategy_returns'].cumsum()[-1])

# plotting strategy historical performance over time
df[['bnh_returns','strategy_returns']] = df[['bnh_returns','strategy_returns']].cumsum()
df[['bnh_returns','strategy_returns']].plot(grid=True, figsize=(12, 8))

Buy and hold returns: -0.3770989996574775
Strategy returns: 1.3603005119382139
INTC buy-and-hold vs TI strategy returns
  • Printing pyfolio strategy QC diagnostics
import pyfolio as pf
pf.create_simple_tear_sheet(df['strategy_returns'].diff())

Start date 2022-01-03
End date 2024-04-19
Total months 27
Backtest
Annual return 68.595%
Cumulative returns 230.676%
Annual volatility 38.018%
Sharpe ratio 1.57
Calmar ratio 2.68
Stability 0.92
Max drawdown -25.626%
Omega ratio 1.31
Sortino ratio 2.56
Skew NaN
Kurtosis NaN
Tail ratio 1.26
Daily value at risk -4.553%
INTC backtesting cumulative returns
  • Plotting INTC backtesting trading signals, BB, MA20 and Close price
df.tail()
           Close    Adj Close    Volume bnh_returns ma20  std  upper_band lower_band signal position strategy_returns
Date           
2024-04-15 36.310001 36.310001 50751600 -0.317231 40.7040 2.792515 46.289030 35.118970 0 1.0 1.420168
2024-04-16 36.259998 36.259998 30607500 -0.318610 40.3815 2.918270 46.218039 34.544961 0 1.0 1.418790
2024-04-17 35.680000 35.680000 41173300 -0.334734 40.0630 3.070239 46.203479 33.922522 0 1.0 1.402665
2024-04-18 35.040001 35.040001 42334400 -0.352834 39.7050 3.221649 46.148299 33.261701 0 1.0 1.384565
2024-04-19 34.200001 34.200001 58968800 -0.377099 39.2940 3.377611 46.049222 32.538778 0 1.0 1.360301

buy_price = []
sell_price = []
prices=df['Close']
for i in range(len(prices)):
    if df['signal'][i] > 0.0:
        buy_price.append(prices[i])
        sell_price.append(np.nan)
    if df['signal'][i] < 0.0:
        sell_price.append(prices[i])
        buy_price.append(np.nan)
    if df["signal"][i] == 0.0:
        sell_price.append(np.nan)
        buy_price.append(np.nan)

plt.figure(figsize=(12,7))
plt.plot(df["Close"], color="black", label="Price")
plt.plot(df.index, buy_price, marker = '^', markersize = 8, color = 'green', linewidth = 0, label = 'BUY SIGNAL')
plt.plot(df.index, sell_price, marker = 'v', markersize = 8, color = 'r', linewidth = 0, label = 'SELL SIGNAL')
plt.plot(df["upper_band"], color="blue", label="Upper BB")
plt.plot(df["lower_band"], color="green", label="Lower BB")
plt.plot(df["ma20"], color="orange", label="MA20")
plt.legend()
plt.grid()
plt.title("Backtesting INTC TI Trading Strategy",fontsize=16)
plt.xlabel("Date",fontsize=16)
plt.ylabel("Close Price USD",fontsize=16)
plt.show()
Backtesting INTC TI Trading Strategy
  • Comparing these results to the ^GSPC cumulative returns
# downloading historical necessary data for backtesting and analysis
_start = dt.date(2022,1,2)
_end = dt.date(2024,4,20)
ticker = '^GSPC'
dfg = yf.download(ticker, start = _start, end = _end)
# calculating buy and hold strategy returns
dfg['bnh_returns'] = np.log(dfg['Adj Close']/dfg['Adj Close'].shift(1))
#dfg.tail(3)
print("^GSPC Buy and Hold returns:",dfg['bnh_returns'].cumsum()[-1])

dfg['daily_return'] = dfg['Close'].pct_change()
# calculate cumluative return
dfg['cum_return'] = np.exp(np.log1p(dfg['daily_return']).cumsum())
print (dfg['cum_return'])
dfg['cum_return'].plot()

^GSPC Buy and Hold returns: 0.03496333020354546
^GSPC cumulative returns

SciPy Portfolio Optimization

  • Let’s consider several popular stochastic simulation techniques of creating an optimized portfolio of our 4 tech assets, for which our investment strategy has the maximum return and minimum risk or max(ROI/Risk) as compared to the S&P 500 benchmark.
  • For example, the Markowitz Mean-Variance Optimization Model is a widely-used framework for constructing portfolios with the best risk-return relationship.
  • Firstly, we estimate expected returns using daily prices as input.
  • Secondly, we invoke the covariance matrix as the most commonly used risk model.
  • Read more about the implemented scipy optimization algorithm and the related PO guide for data scientists.
#Importing Libraries
import numpy as np
import pandas as pd
import yfinance as yf
import matplotlib.pyplot as plt
from scipy.optimize import minimize
from scipy.stats import norm
from scipy.stats import skew, kurtosis
from scipy.stats.mstats import gmean
# Select Optimization Criteria 'sharpe', 'cvar', 'sortino' or 'variance'
optimization_criterion = 'cvar'

#Read input Adj Close prices
symbols = ['NVDA', 'AMD', 'MSI', 'INTC']
start_date = '2022-01-01'
end_date = '2024-04-20'

data = yf.download(symbols, start=start_date, end=end_date)['Adj Close']
data.tail()
Ticker AMD INTC MSI NVDA
Date    
2024-04-15 160.320007 36.310001 338.579987 860.010010
2024-04-16 163.460007 36.259998 340.109985 874.150024
2024-04-17 154.020004 35.680000 340.510010 840.349976
2024-04-18 155.080002 35.040001 339.459991 846.710022
2024-04-19 146.639999 34.200001 339.649994 762.000000

#Calculate daily returns
returns = data.pct_change().dropna()
  • Defining the optimization objective functions , constraints and bounds
def objective_sharpe(weights): 
    return -np.dot(weights, returns.mean()) / np.sqrt(np.dot(weights.T, np.dot(returns.cov() * 252, weights)))
def objective_cvar(weights):
    portfolio_returns = np.dot(returns, weights)
    portfolio_mean = portfolio_returns.mean()
    portfolio_std = portfolio_returns.std()
    conf_level = 0.05  # Confidence level
    cvar = portfolio_mean - portfolio_std * norm.ppf(conf_level)
    return cvar
def objective_sortino(weights):
    portfolio_returns = np.dot(returns, weights)
    downside_returns = portfolio_returns[portfolio_returns < 0]
    downside_std = downside_returns.std()
    sortino_ratio = portfolio_returns.mean() / downside_std
    return -sortino_ratio  
def objective_variance(weights):
    return np.dot(weights.T, np.dot(returns.cov() * 252, weights))

cons = ({'type': 'eq', 'fun': lambda x: np.sum(x) - 1})
bounds = tuple((0, 1) for x in range(len(symbols)))
  • Running the PO algorithm with optimal weights
# Optimization
init_guess = np.array(len(symbols) * [1. / len(symbols),])
if optimization_criterion == 'sharpe':
    opt_results = minimize(objective_sharpe, init_guess, method='SLSQP', bounds=bounds, constraints=cons)
elif optimization_criterion == 'cvar':
    opt_results = minimize(objective_cvar, init_guess, method='SLSQP', bounds=bounds, constraints=cons)
elif optimization_criterion == 'sortino':
    opt_results = minimize(objective_sortino, init_guess, method='SLSQP', bounds=bounds, constraints=cons)
elif optimization_criterion == 'variance':
    opt_results = minimize(objective_variance, init_guess, method='SLSQP', bounds=bounds, constraints=cons)

# Optimal weights
optimal_weights = opt_results.x


# Optimize all criteria
opt_results_cvar = minimize(objective_cvar, init_guess, method='SLSQP', bounds=bounds, constraints=cons)
opt_results_sortino = minimize(objective_sortino, init_guess, method='SLSQP', bounds=bounds, constraints=cons)
opt_results_variance = minimize(objective_variance, init_guess, method='SLSQP', bounds=bounds, constraints=cons)
opt_results_sharpe = minimize(objective_sharpe, init_guess, method='SLSQP', bounds=bounds, constraints=cons)

# Optimal weights for each criterion
optimal_weights_cvar = opt_results_cvar.x
optimal_weights_sortino = opt_results_sortino.x
optimal_weights_variance = opt_results_variance.x
optimal_weights_sharpe = opt_results_sharpe.x
  • Plotting the efficient frontier
port_returns = []
port_volatility = []
sharpe_ratio = []
all_weights = []  # almacena los pesos de todas las carteras simuladas

num_assets = len(symbols)
num_portfolios = 50000

np.random.seed(101)

for single_portfolio in range(num_portfolios):
    weights = np.random.random(num_assets)
    weights /= np.sum(weights)
    returns_portfolio = np.dot(weights, returns.mean()) * 252
    volatility = np.sqrt(np.dot(weights.T, np.dot(returns.cov() * 252, weights)))
    sr = returns_portfolio / volatility
    sharpe_ratio.append(sr)
    port_returns.append(returns_portfolio)
    port_volatility.append(volatility)
    all_weights.append(weights)  # registra los pesos para esta cartera

plt.figure(figsize=(12, 8))
plt.scatter(port_volatility, port_returns, c=sharpe_ratio, cmap='viridis')
plt.colorbar(label='Sharpe Ratio')
plt.xlabel('Volatility',fontsize=14)
plt.ylabel('Return',fontsize=14)
plt.grid()
The efficient frontier plot with optimization_criterion = ‘cvar’
  • Plotting the optimal portfolio for each criterion in the above domain
plt.figure(figsize=(12, 8))
plt.scatter(port_volatility, port_returns, c=sharpe_ratio, cmap='viridis')

opt_returns_cvar = np.dot(optimal_weights_cvar, returns.mean()) * 252
opt_volatility_cvar = np.sqrt(np.dot(optimal_weights_cvar.T, np.dot(returns.cov() * 252, optimal_weights_cvar)))
opt_portfolio_cvar = plt.scatter(opt_volatility_cvar, opt_returns_cvar, color='hotpink', s=250, label='CVaR')

opt_returns_sortino = np.dot(optimal_weights_sortino, returns.mean()) * 252
opt_volatility_sortino = np.sqrt(np.dot(optimal_weights_sortino.T, np.dot(returns.cov() * 252, optimal_weights_sortino)))
opt_portfolio_sortino = plt.scatter(opt_volatility_sortino, opt_returns_sortino, color='g', s=50, label='Sortino')

opt_returns_variance = np.dot(optimal_weights_variance, returns.mean()) * 252
opt_volatility_variance = np.sqrt(np.dot(optimal_weights_variance.T, np.dot(returns.cov() * 252, optimal_weights_variance)))
opt_portfolio_variance = plt.scatter(opt_volatility_variance, opt_returns_variance, color='b', s=50, label='Variance')

opt_returns_sharpe = np.dot(optimal_weights_sharpe, returns.mean()) * 252
opt_volatility_sharpe = np.sqrt(np.dot(optimal_weights_sharpe.T, np.dot(returns.cov() * 252, optimal_weights_sharpe)))
opt_portfolio_sharpe = plt.scatter(opt_volatility_sharpe, opt_returns_sharpe, color='r', s=50, label='Sharpe')


plt.legend(loc='upper left')
plt.colorbar(label='Sharpe Ratio')
plt.xlabel('Volatility',fontsize=14)
plt.ylabel('Return',fontsize=14)
plt.grid()
plt.show()
Optimal portfolio for each criterion in the return-volatility domain
# Function to calculate the maximum drawdown
def max_drawdown(return_series):
    comp_ret = (1 + return_series).cumprod()
    peak = comp_ret.expanding(min_periods=1).max()
    dd = (comp_ret/peak) - 1
    return dd.min()

# Function to calculate more detailed descriptive statistics
def detailed_portfolio_statistics(weights):
    portfolio_returns = returns.dot(weights)
    
    # General descriptive statistics
    mean_return_annualized = gmean(portfolio_returns + 1)**252 - 1
    std_dev_annualized = portfolio_returns.std() * np.sqrt(252)
    skewness = skew(portfolio_returns)
    kurt = kurtosis(portfolio_returns)
    max_dd = max_drawdown(portfolio_returns)
    count = len(portfolio_returns)
    
    # Optimization metrics
    risk_free_rate = 0.00
    sharpe_ratio = (mean_return_annualized - risk_free_rate) / std_dev_annualized
    conf_level = 0.05
    cvar = mean_return_annualized - std_dev_annualized * norm.ppf(conf_level)
    downside_returns = portfolio_returns[portfolio_returns < 0]
    downside_std_dev = downside_returns.std() * np.sqrt(252)
    sortino_ratio = mean_return_annualized / downside_std_dev
    variance = std_dev_annualized ** 2 
    
    return mean_return_annualized, std_dev_annualized, skewness, kurt, max_dd, count, sharpe_ratio, cvar, sortino_ratio, variance

# Calculate statistics for each portfolioCalculate statistics for each portfolio
statistics_cvar = detailed_portfolio_statistics(optimal_weights_cvar)
statistics_sortino = detailed_portfolio_statistics(optimal_weights_sortino)
statistics_variance = detailed_portfolio_statistics(optimal_weights_variance)
statistics_sharpe = detailed_portfolio_statistics(optimal_weights_sharpe)

# Statistics names
statistics_names = ['Annualized return', 'Annualized volatility', 'Skewness', 'Kurtosis', 'Max Drawdown', 'Data content', 'Sharpe Ratio', 'CVaR', 'Sortino Ratio', 'Variance']

# Dictionary that associates the names of optimization methods with optimal weights and statistics
portfolio_data = {
    'CVaR': {
        'weights': optimal_weights_cvar,
        'statistics': detailed_portfolio_statistics(optimal_weights_cvar)
    },
    'Sortino': {
        'weights': optimal_weights_sortino,
        'statistics': detailed_portfolio_statistics(optimal_weights_sortino)
    },
    'Variance': {
        'weights': optimal_weights_variance,
        'statistics': detailed_portfolio_statistics(optimal_weights_variance)
    },
    'Sharpe': {
        'weights': optimal_weights_sharpe,
        'statistics': detailed_portfolio_statistics(optimal_weights_sharpe)
    },
}

# Print the weights and statistics for each optimization method
for method, data in portfolio_data.items():
    print("\n")
    print("========================================================================================================")
    print("\n")
    print(f"Optimum portfolio weights for {method}:")
    print("\n")
    for symbol, weight in zip(symbols, data['weights']):
        if weight < 1e-4:  # considers any weight less than 0.01% as zero
            print(f"{symbol}: practically 0%")
        else:
            print(f"{symbol}: {weight*100:.2f}%")

    print("\n")
    print(f"Descriptive statistics of the optimal portfolio for {method}:")
    print("\n")
    for name, stat in zip(statistics_names, data['statistics']):
        print(f"{name}: {stat*100 if name != 'Data content' else stat:.2f}")

print("\n")
print("========================================================================================================")
========================================================================================================


Optimum portfolio weights for CVaR:


NVDA: practically 0%
AMD: 17.51%
MSI: 82.49%
INTC: practically 0%


Descriptive statistics of the optimal portfolio for CVaR:


Annualized return: 8.12
Annualized volatility: 23.45
Skewness: 24.53
Kurtosis: 197.09
Max Drawdown: -25.46
Data content: 576.00
Sharpe Ratio: 34.63
CVaR: 46.69
Sortino Ratio: 54.29
Variance: 5.50


========================================================================================================


Optimum portfolio weights for Sortino:


NVDA: practically 0%
AMD: practically 0%
MSI: 1.76%
INTC: 98.24%


Descriptive statistics of the optimal portfolio for Sortino:


Annualized return: 49.73
Annualized volatility: 55.35
Skewness: 81.96
Kurtosis: 462.31
Max Drawdown: -61.07
Data content: 576.00
Sharpe Ratio: 89.84
CVaR: 140.77
Sortino Ratio: 158.52
Variance: 30.64


========================================================================================================


Optimum portfolio weights for Variance:


NVDA: practically 0%
AMD: 16.32%
MSI: 83.68%
INTC: practically 0%


Descriptive statistics of the optimal portfolio for Variance:


Annualized return: 8.43
Annualized volatility: 23.45
Skewness: 24.82
Kurtosis: 203.47
Max Drawdown: -25.43
Data content: 576.00
Sharpe Ratio: 35.94
CVaR: 46.99
Sortino Ratio: 56.28
Variance: 5.50


========================================================================================================


Optimum portfolio weights for Sharpe:


NVDA: practically 0%
AMD: practically 0%
MSI: 34.47%
INTC: 65.53%


Descriptive statistics of the optimal portfolio for Sharpe:


Annualized return: 39.65
Annualized volatility: 41.33
Skewness: 61.72
Kurtosis: 313.14
Max Drawdown: -49.28
Data content: 576.00
Sharpe Ratio: 95.93
CVaR: 107.64
Sortino Ratio: 163.20
Variance: 17.08


========================================================================================================

Modern Port Monte Carlo Simulations

  • Let’s delve into the specifics of Markowitz Portfolio Optimization (MPO) by employing the Monte Carlo simulations combined with relevant matplotlib or plotly visualizations of the efficient frontier Markowitz-style.
  • Step 1: MPO data preparation
# Load Packages
import numpy as np
import pandas as pd
from pandas_datareader import data
import matplotlib.pyplot as plt
%matplotlib inline

# Read Data
# Define the ticker list
import pandas as pd
tickers_list = ['NVDA', 'INTC', 'AMD', 'MSI']

# Fetch the data
import yfinance as yf
data = yf.download(tickers_list,'2022-1-1')['Adj Close']

# Print last 5 rows of the data
print(data.tail())

Ticker             AMD       INTC         MSI        NVDA
Date                                                     
2024-04-15  160.320007  36.310001  338.579987  860.010010
2024-04-16  163.460007  36.259998  340.109985  874.150024
2024-04-17  154.020004  35.680000  340.510010  840.349976
2024-04-18  155.080002  35.040001  339.459991  846.710022
2024-04-19  146.639999  34.200001  339.649994  762.000000

#Computing log return covariance and correlation matrices

# Log of percentage change
cov_matrix = data.pct_change().apply(lambda x: np.log(1+x)).cov()
cov_matrix

Ticker AMD INTC MSI NVDA
Ticker    
AMD 0.001175 0.000476 0.000244 0.000956
INTC 0.000476 0.000606 0.000143 0.000418
MSI 0.000244 0.000143 0.000232 0.000250
NVDA 0.000956 0.000418 0.000250 0.001218

corr_matrix = data.pct_change().apply(lambda x: np.log(1+x)).corr()
corr_matrix

Ticker AMD INTC MSI NVDA
Ticker    
AMD 1.000000 0.564464 0.468423 0.798755
INTC 0.564464 1.000000 0.380640 0.486759
MSI 0.468423 0.380640 1.000000 0.469877
NVDA 0.798755 0.486759 0.469877 1.000000

# Volatility is given by the annual standard deviation. We multiply by 250 because there are 250 trading days/year.
ann_sd = data.pct_change().apply(lambda x: np.log(1+x)).std().apply(lambda x: x*np.sqrt(250))
ann_sd

Ticker
AMD     0.541973
INTC    0.389105
MSI     0.240755
NVDA    0.551848
dtype: float64

# Yearly returns for individual companies
ind_er = data.resample('YE').last().pct_change().mean()
ind_er

Ticker
AMD     0.635338
INTC    0.314108
MSI     0.159160
NVDA    1.464477
dtype: float64

assets = pd.concat([ind_er, ann_sd], axis=1) # Creating a table for visualising returns and volatility of assets
assets.columns = ['Returns', 'Volatility']
assets

    Returns Volatility
Ticker  
AMD 0.635338 0.541973
INTC 0.314108 0.389105
MSI 0.159160 0.240755
NVDA 1.464477 0.551848
  • Running 10k portfolios with random weights and plotting the efficient frontier
p_ret = [] # Define an empty array for portfolio returns
p_vol = [] # Define an empty array for portfolio volatility
p_weights = [] # Define an empty array for asset weights

num_assets = len(data.columns)
num_portfolios = 10000

for portfolio in range(num_portfolios):
    weights = np.random.random(num_assets)
    weights = weights/np.sum(weights)
    p_weights.append(weights)
    returns = np.dot(weights, ind_er) # Returns are the product of individual expected returns of asset and its 
                                      # weights 
    p_ret.append(returns)
    var = cov_matrix.mul(weights, axis=0).mul(weights, axis=1).sum().sum()# Portfolio Variance
    sd = np.sqrt(var) # Daily standard deviation
    ann_sd = sd*np.sqrt(250) # Annual standard deviation = volatility
    p_vol.append(ann_sd)

data1 = {'Returns':p_ret, 'Volatility':p_vol}

for counter, symbol in enumerate(data.columns.tolist()):
    #print(counter, symbol)
    data1[symbol+' weight'] = [w[counter] for w in p_weights]

portfolios  = pd.DataFrame(data1)
portfolios.tail() # Dataframe of the 10000 portfolios created

Returns Volatility AMD weight INTC weight MSI weight NVDA weight
9995 0.771793 0.405336 0.318910 0.208203 0.144603 0.328284
9996 0.852389 0.392365 0.130841 0.255292 0.160822 0.453046
9997 0.665961 0.378391 0.295835 0.288311 0.169740 0.246115
9998 0.801484 0.383952 0.222032 0.066961 0.307869 0.403137
9999 0.676878 0.429700 0.505008 0.247905 0.064119 0.182969

# Plot efficient frontier
portfolios.plot.scatter(x='Volatility', y='Returns', marker='o', s=10, alpha=0.3, grid=True, figsize=[5,5])
Efficient frontier of 10k random portfolios
  • Creating the minimum Volatility portfolio
min_vol_port = portfolios.iloc[portfolios['Volatility'].idxmin()]
# idxmin() gives us the minimum value in the column specified.                               
min_vol_port
Returns        0.222657
Volatility     0.235856
AMD weight     0.005248
INTC weight    0.146243
MSI weight     0.819138
NVDA weight    0.029371
Name: 7829, dtype: float64

# plotting the minimum volatility portfolio
plt.subplots(figsize=[7,7])
plt.scatter(portfolios['Volatility'], portfolios['Returns'],marker='o', s=10, alpha=0.3)
plt.scatter(min_vol_port[1], min_vol_port[0], color='r', marker='*', s=500)
plt.xlabel('Volatility',fontsize=14)
plt.ylabel('Returns',fontsize=14)
plt.title("Minimum Volatility Portfolio",fontsize=16)
plt.grid()
Minimum Volatility portfolio
  • Finding the optimal portfolio max Sharpe
# Finding the optimal portfolio max Sharpe
rf = 0.01 # risk factor
optimal_risky_port = portfolios.iloc[((portfolios['Returns']-rf)/portfolios['Volatility']).idxmax()]
optimal_risky_port

Returns        1.320434
Volatility     0.507973
AMD weight     0.020084
INTC weight    0.033438
MSI weight     0.068125
NVDA weight    0.878353
Name: 5210, dtype: float64
  • Plotting both portfolios and the efficient frontier
# Plotting optimal portfolio
plt.subplots(figsize=(8, 8))
plt.scatter(portfolios['Volatility'], portfolios['Returns'],marker='o', s=10, alpha=0.3)
plt.scatter(min_vol_port[1], min_vol_port[0], color='r', marker='*', s=500)
plt.scatter(optimal_risky_port[1], optimal_risky_port[0], color='g', marker='*', s=500)
plt.xlabel('Volatility',fontsize=14)
plt.ylabel('Returns',fontsize=14)
plt.title("Minimum Volatility (Red) vs Optimal Risky (Green) Portfolio",fontsize=14)
plt.grid()
Minimum Volatility, max Sharpe portfolios and the efficient frontier.

Monte Carlo vs SciPy 2Y MPO

# Load Packages
import numpy as np 
import pandas as pd 
import matplotlib.pyplot as plt
import plotly.express as px
import pandas_datareader as web
from datetime import datetime as dt, timedelta as td

end = dt.today()
start = end - td(days=2*365)

#option 1
stocks = ['NVDA', 'INTC', 'AMD', 'MSI','^GSPC']
#option 2
stocks = ['NVDA', 'INTC', 'AMD', 'MSI']

# Fetch the data
import yfinance as yf
df = yf.download(stocks,start=start,end=end)['Adj Close']
  • Plotting the normalized stock prices scaled by 100
px.line(df * 100 / df.iloc[0]) #cf. Stock Returns vs Benchmark
  • Plotting the daily percentage changes
ret_port = df.pct_change() 
px.line(ret_port) #cf. Stock Returns vs Benchmark
  • Plotting the stock cumulative return
cumretport = (1 + ret_port).cumprod() - 1 
px.line(cumretport*100) #cf. Stock Returns vs Benchmark
print(log_ret.mean())  # option 1

Ticker
AMD      0.001018
INTC    -0.000502
MSI      0.000876
NVDA     0.002727
^GSPC    0.000302
dtype: float64
  • Calculating the expected return and volatility for 1k random portfolios (cf. option 2)
np.random.seed(1)
# Weight each security
weights = np.random.random((4,1))
# normalize it, so that some is one
weights /= np.sum(weights)
print(f'Normalized Weights : {weights.flatten()}')

# We generally do log return instead of return
log_ret = np.log(df / df.shift(1))
log_ret

# Expected return (weighted sum of mean returns). Mult by 252 as we always do annual calculation and year has 252 business days
exp_ret = log_ret.mean()[:-1].dot(weights)*252 
print(f'\nExpected return of the portfolio is : {exp_ret[0]}')

# Exp Volatility (Risk)
exp_vol = np.sqrt(weights.T.dot(252*log_ret.cov().dot(weights)))
print(f'\nVolatility of the portfolio: {exp_vol[0][0]}')

# Sharpe ratio
sr = exp_ret / exp_vol
print(f'\nSharpe ratio of the portfolio: {sr[0][0]}')

Normalized Weights : [2.89640161e-01 5.00297106e-01 7.94383512e-05 2.09983296e-01]

# number of simulations
n = 1000

port_weights = np.zeros(shape=(n,len(df.columns)))
port_volatility = np.zeros(n)
port_sr = np.zeros(n)
port_return = np.zeros(n)

num_securities = len(df.columns)
# num_securities
for i in range(n):
    # Weight each security
    weights = np.random.random(4)
    # normalize it, so that some is one
    weights /= np.sum(weights)
    port_weights[i,:] = weights 
    #     print(f'Normalized Weights : {weights.flatten()}')

    # Expected return (weighted sum of mean returns). Mult by 252 as we always do annual calculation and year has 252 business days
    exp_ret = log_ret.mean().dot(weights)*252 
    port_return[i] = exp_ret
#     print(f'\nExpected return is : {exp_ret[0]}')

    # Exp Volatility (Risk)
    exp_vol = np.sqrt(weights.T.dot(252*log_ret.cov().dot(weights)))
    port_volatility[i] = exp_vol
#     print(f'\nVolatility : {exp_vol[0][0]}')

    # Sharpe ratio
    sr = exp_ret / exp_vol
    port_sr[i] = sr
#     print(f'\nSharpe ratio : {sr[0][0]}')
  • Finding the return and volatility at max Sharpe Ratio (SR)
# Index of max Sharpe Ratio
max_sr = port_sr.max()
ind = port_sr.argmax()
# Return and Volatility at Max SR
max_sr_ret = port_return[ind]
max_sr_vol = port_volatility[ind]
  • Plotting the efficient frontier and the max SR portfolio
plt.figure(figsize=(10,6))
plt.scatter(port_volatility,port_return,c=port_sr, cmap='plasma')
plt.colorbar(label='Sharpe Ratio')
plt.xlabel('Volatility', fontsize=15)
plt.ylabel('Return', fontsize=15)
plt.title('Efficient Frontier (Bullet Plot)', fontsize=15)
plt.scatter(max_sr_vol, max_sr_ret, c='blue', s=150, edgecolors='red', marker='o', label='Max \
Sharpe Ratio Portfolio')
plt.legend();
Efficient frontier and the max Sharpe Ratio portfolio
  • Optimized portfolio weights, expected returns and volatility
for weight, stock in zip(port_weights[ind],stocks):
    print(f'{round(weight * 100, 2)} % of {stock} should be bought.')
    
# best portfolio return option 2
print(f'\nMarkowitz optimal portfolio return is : {round(max_sr_ret * 100, 2)}% with volatility \
{max_sr_vol}')

5.69 % of NVDA should be bought.
1.35 % of INTC should be bought.
38.94 % of AMD should be bought.
54.02 % of MSI should be bought.

Markowitz optimal portfolio return is : 45.45% with volatility 0.3632750947781604
  • Using SciPy to get the max of Sharpe Ratio
#SciPy to get the max of Sharpe Ratio
from scipy import optimize
log_mean = log_ret.mean() * 252
cov = log_ret.cov() * 252

# Some helper functions
def get_ret_vol_sr(weights):
    weights = np.array(weights)
    ret = log_mean.dot(weights)
    vol = np.sqrt(weights.T.dot(cov.dot(weights)))
    sr = ret / vol
    return np.array([ret, vol, sr])

# Negate Sharpe ratio as we need to max it but Scipy minimize the given function
def neg_sr(weights):
    return get_ret_vol_sr(weights)[-1] * -1

# check sum of weights 
def check_sum(weights):
    return np.sum(weights) - 1

# Constraints for the optimization problem
cons = {'type':'eq','fun':check_sum}
# bounds on weights
bounds = ((0,1),(0,1),(0,1),(0,1))
# initial guess for optimization to start with
init_guess = [.25 for _ in range(4)]


# Call minimizer
opt_results = optimize.minimize(neg_sr, init_guess, constraints=cons, bounds=bounds, method='SLSQP')

optimal_weights = opt_results.x
# optimal_weights
for st, i in zip(stocks,optimal_weights):
    print(f'Stock {st} has weight {np.round(i*100,2)} %')

Stock NVDA has weight 0.0 %
Stock INTC has weight 0.0 %
Stock AMD has weight 47.28 %
Stock MSI has weight 52.72 %

#Monte Carlo weights

mc_weights = port_weights[ind]
for st, i in zip(stocks,mc_weights):
    print(f'Stock {st} has weight {np.round(i*100,2)} %')

Stock NVDA has weight 5.69 %
Stock INTC has weight 1.35 %
Stock AMD has weight 38.94 %
Stock MSI has weight 54.02 %

# Comparing two results we see that we get very close results
(optimal_weights - mc_weights)

array([-0.05690935, -0.01352879,  0.08342671, -0.01298856])
  • Comparing expected returns and volatility
get_ret_vol_sr(optimal_weights), get_ret_vol_sr(mc_weights)

print('For a given portfolio we have: (Using SciPy optimizer)\n \n')
for i, j in enumerate('Return Volatility SharpeRatio'.split()):
    print(f'{j} is : {get_ret_vol_sr(optimal_weights)[i]}\n')
    
print('For a given portfolio we have: (Using Monte Carlo)\n \n')
for i, j in enumerate('Return Volatility SharpeRatio'.split()):
    print(f'{j} is : {get_ret_vol_sr(mc_weights)[i]}\n')

For a given portfolio we have: (Using SciPy optimizer)

Return is : 0.45084758839098316

Volatility is : 0.34220896907233184

SharpeRatio is : 1.3174628052945294

For a given portfolio we have: (Using Monte Carlo)

Return is : 0.45447440930271593

Volatility is : 0.3632750947781604

SharpeRatio is : 1.2510475279904554
  • Plotting the efficient frontier curve vs max SR portfolio
#Frontier curve
#Best return for given volatility or vice versa.
frontier_y = np.linspace(port_return.min(), port_return.max(), 100)
frontier_vol = []

def minimize_vol(weights):
    return get_ret_vol_sr(weights)[1]

for possible_ret in frontier_y:
    cons = ({'type':'eq','fun':check_sum},
            {'type':'eq','fun':lambda w:get_ret_vol_sr(w)[0] - possible_ret})
    result = optimize.minimize(minimize_vol, init_guess, method='SLSQP', constraints=cons, bounds=bounds)
    frontier_vol.append(result['fun'])  

plt.figure(figsize=(10,6))
plt.scatter(port_volatility,port_return,c=port_sr, cmap='plasma')
plt.colorbar(label='Sharpe Ratio')
plt.xlabel('Volatility', fontsize=15)
plt.ylabel('Return', fontsize=15)
plt.title('Efficient Frontier', fontsize=15)
plt.scatter(max_sr_vol, max_sr_ret, c='blue', s=150, edgecolors='red', marker='o')

plt.plot(frontier_vol, frontier_y, c='magenta', ls='--', lw=3, label='Efficient Frontier')
plt.legend();
Efficient frontier curve vs max SR portfolio

Quantstats Portfolio Report Before MPO

  • We employ Quantstats to understand portfolio performance better by examining in-depth analytics and risk metrics vs ^GSPC.
  • Our initial portfolio consists of 4 tech stocks (option 2) with equal weights 0.25, viz.
weights = [0.25, 0.25, 0.25, 0.25] # Defining weights for each stock
portfolio = df['NVDA']*weights[0] + df['AMD']*weights[1] + df['INTC']*weights[2] + df['MSI']*weights[3] # Creating portfolio multiplying each stock for its respective weight 
portfolio # Portfolio before MPO

Date
2022-04-19    148.027820
2022-04-20    146.227382
2022-04-21    140.810877
2022-04-22    136.540077
2022-04-25    138.295864
                 ...    
2024-04-12    356.159995
2024-04-15    348.805001
2024-04-16    353.495004
2024-04-17    342.639997
2024-04-18    347.843740
Length: 503, dtype: float64
  • Plotting the full portfolio report vs ^GSPC benchmark
qs.reports.full(portfolio, benchmark = df['^GSPC'])

Performance Metrics

                           Benchmark    Strategy
-------------------------  -----------  ----------
Start Period               2022-04-20   2022-04-20
End Period                 2024-04-18   2024-04-18
Risk-Free Rate             0.0%         0.0%
Time in Market             100.0%       100.0%

Cumulative Return          13.12%       134.99%
CAGR﹪                     4.35%        34.36%

Sharpe                     0.43         1.41
Prob. Sharpe Ratio         72.72%       97.91%
Smart Sharpe               0.42         1.37
Sortino                    0.61         2.26
Smart Sortino              0.6          2.19
Sortino/√2                 0.43         1.6
Smart Sortino/√2           0.42         1.55
Omega                      1.27         1.27

Max Drawdown               -19.79%      -31.21%
Longest DD Days            447          287
Volatility (ann.)          18.32%       34.63%
R^2                        0.64         0.64
Information Ratio          0.11         0.11
Calmar                     0.22         1.1
Skew                       -0.11        0.55
Kurtosis                   2.03         2.88

Expected Daily %           0.02%        0.17%
Expected Monthly %         0.49%        3.48%
Expected Yearly %          4.2%         32.95%
Kelly Criterion            1.98%        12.12%
Risk of Ruin               0.0%         0.0%
Daily Value-at-Risk        -1.87%       -3.39%
Expected Shortfall (cVaR)  -1.87%       -3.39%

Max Consecutive Wins       8            11
Max Consecutive Losses     6            7
Gain/Pain Ratio            0.08         0.27
Gain/Pain (1M)             0.31         1.27

Payoff Ratio               1.03         1.16
Profit Factor              1.08         1.27
Common Sense Ratio         1.24         1.6
CPC Index                  0.56         0.78
Tail Ratio                 1.15         1.26
Outlier Win Ratio          4.82         2.45
Outlier Loss Ratio         5.33         2.88

MTD                        -3.93%       -6.19%
3M                         6.51%        28.51%
6M                         15.42%       60.21%
YTD                        5.83%        38.46%
1Y                         21.59%       104.94%
3Y (ann.)                  4.35%        34.36%
5Y (ann.)                  4.35%        34.36%
10Y (ann.)                 4.35%        34.36%
All-time (ann.)            4.35%        34.36%

Best Day                   5.54%        11.53%
Worst Day                  -4.32%       -6.06%
Best Month                 9.11%        18.49%
Worst Month                -9.34%       -14.91%
Best Year                  24.23%       104.95%
Worst Year                 -13.96%      -17.19%

Avg. Drawdown              -2.28%       -3.72%
Avg. Drawdown Days         30           18
Recovery Factor            0.79         3.12
Ulcer Index                0.09         0.1
Serenity Index             0.13         1.12

Avg. Up Month              4.66%        11.94%
Avg. Down Month            -5.78%       -9.36%
Win Days %                 50.2%        52.79%
Win Month %                60.0%        64.0%
Win Quarter %              55.56%       55.56%
Win Year %                 66.67%       66.67%

Beta                       -            1.52
Alpha                      -            0.37
Correlation                -            80.15%
Treynor Ratio              -            89.09%
None
Worst 5 Drawdowns
Start Valley End Days Max Drawdown 99% Max Drawdown
1 2022-04-21 2022-10-14 2023-02-01 287 -31.213813 -28.614034
2 2023-09-01 2023-10-26 2023-11-07 68 -12.313689 -11.760164
3 2024-03-26 2024-04-17 2024-04-18 24 -9.736568 -8.365719
4 2023-07-19 2023-08-11 2023-08-30 43 -8.844754 -7.638776
5 2023-02-15 2023-02-22 2023-03-07 21 -6.694283 -6.039259

Strategy Visualization
Portfolio before MPO: Cumulative Returns vs Benchmark.
Portfolio before MPO: Cumulative Returns vs Benchmark (Volatility Matched).
Portfolio before MPO: EOY Returns vs Benchmark
Portfolio before MPO: Distribution of Monthly Returns vs Daily Active Returns.
Portfolio before MPO: 6-months rolling volatility and rolling beta to benchmark.
Portfolio before MPO: 6-months rolling Sharpe and Sortino ratios.
Portfolio before MPO: Strategy-Worst 5 Drawdown Periods vs Underwater Plot
Portfolio before MPO: Strategy-Monthly Active Returns (%)
Portfolio before MPO: Strategy-Return Quantiles

Quantstats Portfolio Report After MPO

  • Our updated portfolio after MPO consists of 4 tech stocks (option 2) with optimized weights, viz.
#Optimized max Sharpe Ratio SciPy 
weights = [0.06, 0.39, 0.01, 0.54] # Defining weights for each stock
portfolio = df['NVDA']*weights[0] + df['AMD']*weights[1] + df['INTC']*weights[2] + df['MSI']*weights[3] # Creating portfolio multiplying each stock for its respective weight 
portfolio # Portfolio after MPO

Date
2022-04-19    174.796358
2022-04-20    174.686317
2022-04-21    170.144846
2022-04-22    164.859244
2022-04-25    166.153715
                 ...    
2024-04-12    302.605097
2024-04-15    297.321696
2024-04-16    300.220396
2024-04-17    294.721005
2024-04-18    296.741143
Length: 503, dtype: float64
  • Plotting the optimized portfolio report vs ^GSPC benchmark
qs.reports.full(portfolio, benchmark = df['^GSPC'])

Performance Metrics

                           Benchmark    Strategy
-------------------------  -----------  ----------
Start Period               2022-04-20   2022-04-20
End Period                 2024-04-18   2024-04-18
Risk-Free Rate             0.0%         0.0%
Time in Market             100.0%       100.0%

Cumulative Return          13.12%       69.76%
CAGR﹪                     4.35%        20.08%

Sharpe                     0.43         1.14
Prob. Sharpe Ratio         72.72%       94.8%
Smart Sharpe               0.4          1.07
Sortino                    0.61         1.77
Smart Sortino              0.58         1.66
Sortino/√2                 0.43         1.25
Smart Sortino/√2           0.41         1.17
Omega                      1.22         1.22

Max Drawdown               -19.79%      -23.87%
Longest DD Days            447          177
Volatility (ann.)          18.32%       26.29%
R^2                        0.66         0.66
Information Ratio          0.09         0.09
Calmar                     0.22         0.84
Skew                       -0.11        0.28
Kurtosis                   2.03         1.91

Expected Daily %           0.02%        0.11%
Expected Monthly %         0.49%        2.14%
Expected Yearly %          4.2%         19.29%
Kelly Criterion            1.14%        9.95%
Risk of Ruin               0.0%         0.0%
Daily Value-at-Risk        -1.87%       -2.61%
Expected Shortfall (cVaR)  -1.87%       -2.61%

Max Consecutive Wins       8            8
Max Consecutive Losses     6            7
Gain/Pain Ratio            0.08         0.22
Gain/Pain (1M)             0.31         1.1

Payoff Ratio               1.02         1.14
Profit Factor              1.08         1.22
Common Sense Ratio         1.24         1.56
CPC Index                  0.55         0.72
Tail Ratio                 1.15         1.28
Outlier Win Ratio          4.23         2.88
Outlier Loss Ratio         4.75         3.39

MTD                        -3.93%       -6.31%
3M                         6.51%        11.03%
6M                         15.42%       32.87%
YTD                        5.83%        15.78%
1Y                         21.59%       43.52%
3Y (ann.)                  4.35%        20.08%
5Y (ann.)                  4.35%        20.08%
10Y (ann.)                 4.35%        20.08%
All-time (ann.)            4.35%        20.08%

Best Day                   5.54%        7.53%
Worst Day                  -4.32%       -5.35%
Best Month                 9.11%        17.09%
Worst Month                -9.34%       -11.76%
Best Year                  24.23%       49.61%
Worst Year                 -13.96%      -2.0%

Avg. Drawdown              -2.28%       -3.14%
Avg. Drawdown Days         30           19
Recovery Factor            0.79         2.51
Ulcer Index                0.09         0.07
Serenity Index             0.13         1.13

Avg. Up Month              4.78%        8.58%
Avg. Down Month            -5.73%       -6.69%
Win Days %                 50.2%        51.99%
Win Month %                60.0%        60.0%
Win Quarter %              55.56%       66.67%
Win Year %                 66.67%       66.67%

Beta                       -            1.16
Alpha                      -            0.21
Correlation                -            80.94%
Treynor Ratio              -            60.06%
None
Worst 5 Drawdowns
Start Valley End Days Max Drawdown 99% Max Drawdown
1 2022-08-17 2022-10-14 2023-02-09 177 -23.867018 -20.927214
2 2022-04-21 2022-06-16 2022-08-01 103 -16.555311 -14.846316
3 2023-07-26 2023-10-27 2023-11-02 100 -9.848466 -9.803296
4 2024-03-08 2024-04-17 2024-04-18 42 -7.452712 -6.818356
5 2023-02-16 2023-02-22 2023-03-15 28 -4.578890 -4.128242
Strategy Visualization
Portfolio after MPO: Cumulative Returns vs Benchmark.
Portfolio after MPO: Cumulative Returns vs Benchmark (Volatility Matched).
Portfolio after MPO: EOY Returns vs Benchmark
Portfolio after MPO: Distribution of Monthly Returns, Daily Active Returns, and Rolling Beta to Benchmark.
Portfolio after MPO: 6-months rolling volatility, Sharpe and Sortino ratios.
Portfolio after MPO: Strategy-Worst 5 Drawdown Periods vs Underwater Plot
Portfolio after MPO: Strategy-Monthly Active Returns (%)
Portfolio after MPO: Strategy-Return Quantiles

Conclusions

  • In this post, we have addressed the challenge of Financial Risk Management (FRM) for Automated Trading (AT) and Investments in Stocks.
  • We have implemented and tested state-of-the art FRM tools and techniques in stock AT and investments.
  • We have deployed a set of SaaS products to open and close trades according to set rules such as points of price movement in an underlying market. Once the current market conditions match any predetermined criteria, our trading algorithms (algos) can execute a buy or sell order on your behalf.
  • As a pilot project, we have used these products to perform robust backtesting, technical/fundamental financial analysis, and stochastic portfolio optimization of 4 tech game-changers (NVDA, AMD, INTC & MSI) vs S&P 500 benchmark.
  • Our interactive stock screening and portfolio optimization dashboard can quickly and easily see the asset’s health at a glance and identify areas that require attention. In addition, our fintech KPI visualizations can communicate the risks associated with specific investments.
  • Overall, we have looked at AT use-case examples based on best fintech industry practices that set to accelerate the AT market growth in the near future. Factors such as the increasing adoption of numerical optimization and stochastic simulation methods, real-time data analytics, interactive visualizations, and the rising demand for automated trading systems substantiate the great business value of our study.

Explore More

Acknowledgements

References

Relevant 3rd Party SaaS Platforms

Stock Market Research Updates

Tutorials for Beginners

Contacts

Python
Algorithmic Trading
Optimization
Investment
Tech
Recommended from ReadMedium