{ "cells": [ { "cell_type": "markdown", "id": "5f6ccd5b", "metadata": {}, "source": [ "# CapiPort - PORTFOLIO OPTIMISATION" ] }, { "cell_type": "markdown", "id": "b1962897", "metadata": {}, "source": [ " Two things to consider for Portfolio Optimisation:\n", " \n", " 1) Minimising Risk\n", " 2) Maximising Return" ] }, { "cell_type": "markdown", "id": "9d025126", "metadata": {}, "source": [ " Basic process of Portfolio Optimisation:\n", " \n", " 1) Select the Asset class to work on.\n", " 1.1) Asset Class choosen - Equity (Stocks)\n", " 2) Select the Companies which you want to use to build a Portfolio.\n", " 2.1) Companies choosen - \n", " 2.1.1) Tata Power - TATAPOWER.NS\n", " 2.1.2) Tata Motors - TATAMOTORS.NS\n", " 2.1.3) Tata Steel - TATASTEEL.NS\n", " 2.1.4) Zomato - ZOMATO.NS\n", " 2.1.5) NHPC - NHPC.NS\n", " 2.1.6) NCC - NCC.NS\n", " 2.1.7) IREDA - IREDA.NS\n", " 2.1.8) IRCON - IRCON.NS\n", " 3) To try various Statistical Methods relating to Portfolio Optimisation.\n", " 3.1) Method 1 - Result\n", " 3.2) Method 2 - Result\n", " 4) You will obtain Weigths or Percentages of Portfolio to invest.\n", " 4.1) Method 1 - Weights\n", " 4.2) Method 2 - Weights\n", " 5) Testing the Portfolio for the future.\n", " 5.1) Method 1 - Result\n", " 5.2) Method 2 - Result\n", " 6) Final Result" ] }, { "cell_type": "code", "execution_count": 15, "id": "9171f5d8", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
SYMBOLNAME OF COMPANYSERIESDATE OF LISTINGPAID UP VALUEMARKET LOTISIN NUMBERFACE VALUEUnnamed: 8YahooEquivYahoo_Equivalent_Code
020MICRONS20 Microns LimitedEQ06-Oct-0851INE144J010275.NS20MICRONS.NS'20MICRONS.NS',
121STCENMGM21st Century Management Services LimitedEQ03-May-95101INE253B0101510.NS21STCENMGM.NS'21STCENMGM.NS',
23IINFOTECH3i Infotech LimitedEQ22-Apr-05101INE748C0102010.NS3IINFOTECH.NS'3IINFOTECH.NS',
33MINDIA3M India LimitedEQ13-Aug-04101INE470A0101710.NS3MINDIA.NS'3MINDIA.NS',
43PLAND3P Land Holdings LimitedEQ19-Jul-9521INE105C010232.NS3PLAND.NS'3PLAND.NS',
....................................
1660ZODJRDMKJZodiac JRD- MKJ LimitedEQ19-Jul-95101INE077B0101810.NSZODJRDMKJ.NS'ZODJRDMKJ.NS',
1661ZOTAZota Health Care LImitedEQ19-Aug-19101INE358U0101210.NSZOTA.NS'ZOTA.NS',
1662ZUARIZuari Agro Chemicals LimitedEQ27-Nov-12101INE840M0101610.NSZUARI.NS'ZUARI.NS',
1663ZUARIGLOBZuari Global LimitedBE12-Apr-95101INE217A0101210.NSZUARIGLOB.NS'ZUARIGLOB.NS',
1664ZYDUSWELLZydus Wellness LimitedEQ13-Nov-09101INE768C0101010.NSZYDUSWELL.NS'ZYDUSWELL.NS'
\n", "

1665 rows × 11 columns

\n", "
" ], "text/plain": [ " SYMBOL NAME OF COMPANY SERIES \\\n", "0 20MICRONS 20 Microns Limited EQ \n", "1 21STCENMGM 21st Century Management Services Limited EQ \n", "2 3IINFOTECH 3i Infotech Limited EQ \n", "3 3MINDIA 3M India Limited EQ \n", "4 3PLAND 3P Land Holdings Limited EQ \n", "... ... ... ... \n", "1660 ZODJRDMKJ Zodiac JRD- MKJ Limited EQ \n", "1661 ZOTA Zota Health Care LImited EQ \n", "1662 ZUARI Zuari Agro Chemicals Limited EQ \n", "1663 ZUARIGLOB Zuari Global Limited BE \n", "1664 ZYDUSWELL Zydus Wellness Limited EQ \n", "\n", " DATE OF LISTING PAID UP VALUE MARKET LOT ISIN NUMBER FACE VALUE \\\n", "0 06-Oct-08 5 1 INE144J01027 5 \n", "1 03-May-95 10 1 INE253B01015 10 \n", "2 22-Apr-05 10 1 INE748C01020 10 \n", "3 13-Aug-04 10 1 INE470A01017 10 \n", "4 19-Jul-95 2 1 INE105C01023 2 \n", "... ... ... ... ... ... \n", "1660 19-Jul-95 10 1 INE077B01018 10 \n", "1661 19-Aug-19 10 1 INE358U01012 10 \n", "1662 27-Nov-12 10 1 INE840M01016 10 \n", "1663 12-Apr-95 10 1 INE217A01012 10 \n", "1664 13-Nov-09 10 1 INE768C01010 10 \n", "\n", " Unnamed: 8 YahooEquiv Yahoo_Equivalent_Code \n", "0 .NS 20MICRONS.NS '20MICRONS.NS', \n", "1 .NS 21STCENMGM.NS '21STCENMGM.NS', \n", "2 .NS 3IINFOTECH.NS '3IINFOTECH.NS', \n", "3 .NS 3MINDIA.NS '3MINDIA.NS', \n", "4 .NS 3PLAND.NS '3PLAND.NS', \n", "... ... ... ... \n", "1660 .NS ZODJRDMKJ.NS 'ZODJRDMKJ.NS', \n", "1661 .NS ZOTA.NS 'ZOTA.NS', \n", "1662 .NS ZUARI.NS 'ZUARI.NS', \n", "1663 .NS ZUARIGLOB.NS 'ZUARIGLOB.NS', \n", "1664 .NS ZYDUSWELL.NS 'ZYDUSWELL.NS' \n", "\n", "[1665 rows x 11 columns]" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import pandas as pd\n", "\n", "df = pd.read_csv(\"EQUITY_L.csv\")\n", "\n", "df.head(1665)" ] }, { "cell_type": "code", "execution_count": 4, "id": "5ff9d0e7", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0 20MICRONS.NS\n", "1 21STCENMGM.NS\n", "2 3IINFOTECH.NS\n", "3 3MINDIA.NS\n", "4 3PLAND.NS\n", " ... \n", "1660 ZODJRDMKJ.NS\n", "1661 ZOTA.NS\n", "1662 ZUARI.NS\n", "1663 ZUARIGLOB.NS\n", "1664 ZYDUSWELL.NS\n", "Name: SYMBOL, Length: 1665, dtype: object" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df['SYMBOL']+'.NS'" ] }, { "cell_type": "code", "execution_count": 6, "id": "d0ee48d8", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0 20 Microns Limited\n", "1 21st Century Management Services Limited\n", "2 3i Infotech Limited\n", "3 3M India Limited\n", "4 3P Land Holdings Limited\n", " ... \n", "1660 Zodiac JRD- MKJ Limited\n", "1661 Zota Health Care LImited\n", "1662 Zuari Agro Chemicals Limited\n", "1663 Zuari Global Limited\n", "1664 Zydus Wellness Limited\n", "Name: NAME OF COMPANY, Length: 1665, dtype: object" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df[\"NAME OF COMPANY\"]" ] }, { "cell_type": "code", "execution_count": 11, "id": "4bfd267c", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0 20MICRONS.NS'\n", "1 21STCENMGM.NS'\n", "2 3IINFOTECH.NS'\n", "3 3MINDIA.NS'\n", "4 3PLAND.NS'\n", " ... \n", "1660 ZODJRDMKJ.NS'\n", "1661 ZOTA.NS'\n", "1662 ZUARI.NS'\n", "1663 ZUARIGLOB.NS'\n", "1664 ZYDUSWELL.NS\n", "Name: Yahoo_Equivalent_Code, Length: 1665, dtype: object" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [] }, { "cell_type": "markdown", "id": "76496c3d", "metadata": {}, "source": [ "## Importing the Libraries" ] }, { "cell_type": "code", "execution_count": 15, "id": "bdaab00e", "metadata": {}, "outputs": [], "source": [ "import yfinance as yf\n", "\n", "\n", "from scipy.optimize import minimize\n", "\n", "\n", "\n", "import pandas as pd\n", "import numpy as np\n", "import matplotlib.pyplot as plt" ] }, { "cell_type": "markdown", "id": "0d4befd2", "metadata": {}, "source": [ "## Get Stock Data" ] }, { "cell_type": "code", "execution_count": 16, "id": "33dc5711", "metadata": {}, "outputs": [], "source": [ "def get_historical_returns(tickers, start_date, end_date):\n", " \"\"\"\n", " Fetch historical returns data for the given tickers.\n", "\n", " Args:\n", " - tickers: list of strings, tickers of assets\n", " - start_date: string, start date in the format 'YYYY-MM-DD'\n", " - end_date: string, end date in the format 'YYYY-MM-DD'\n", "\n", " Returns:\n", " - pandas DataFrame, historical returns data\n", " \"\"\"\n", " data = yf.download(tickers, start=start_date, end=end_date)['Adj Close']\n", " returns = data.pct_change().dropna()\n", " return returns\n", "\n", "def get_risk_free_rate_india():\n", " \"\"\"\n", " Get the risk-free rate for the Indian market using the yield of the 10-year Indian Government Bond.\n", "\n", " Returns:\n", " - float, risk-free rate\n", " \"\"\"\n", " # Ticker symbol for the 10-year Indian Government Bond yield\n", " bond_ticker = 'INR=X' # You can replace this with the actual ticker symbol for the bond\n", "\n", " # Fetch the bond data\n", " bond_data = yf.Ticker(bond_ticker)\n", "\n", " # Get the latest yield\n", " risk_free_rate_india = bond_data.history(period='1d')['Close'][-1] / 100\n", " return risk_free_rate_india" ] }, { "cell_type": "code", "execution_count": 26, "id": "3fec74c6", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "[*********************100%%**********************] 8 of 8 completed\n", "/var/folders/jx/_r4pg95j3pzdd581p_wql9pc0000gn/T/ipykernel_17224/562231645.py:14: FutureWarning: The default fill_method='pad' in DataFrame.pct_change is deprecated and will be removed in a future version. Call ffill before calling pct_change to retain current behavior and silence this warning.\n", " returns = data.pct_change().dropna()\n", "/var/folders/jx/_r4pg95j3pzdd581p_wql9pc0000gn/T/ipykernel_17224/4250087689.py:15: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", " risk_free_rate_india = bond_data.history(period='1d')['Close'][-1] / 100\n" ] } ], "source": [ "equity_list = [\"TATAPOWER.NS\", \"TATAMOTORS.NS\", \"TATASTEEL.NS\", \"ZOMATO.NS\", \"NHPC.NS\", \"NCC.NS\", \"IREDA.NS\", \"IRCON.NS\"]\n", "\n", "equity_data = get_historical_returns(equity_list, \"1900-01-01\", \"2024-03-04\")\n", "\n", "risk_free_rate = get_risk_free_rate_india()" ] }, { "cell_type": "code", "execution_count": 28, "id": "70190a08", "metadata": {}, "outputs": [], "source": [ "def sharpe_ratio(weights, returns, risk_free_rate):\n", " \"\"\"\n", " Calculate the Sharpe Ratio of a portfolio.\n", "\n", " Args:\n", " - weights: array-like, weights of assets in the portfolio\n", " - returns: pandas DataFrame, historical returns of assets\n", " - risk_free_rate: float, risk-free rate of return\n", "\n", " Returns:\n", " - float, Sharpe Ratio of the portfolio\n", " \"\"\"\n", " portfolio_return = np.sum(weights * returns.mean() * 252) # 252 trading days in a year\n", " portfolio_std_dev = np.sqrt(np.dot(weights.T, np.dot(returns.cov() * 252, weights)))\n", " sharpe_ratio = (portfolio_return - risk_free_rate) / portfolio_std_dev\n", " return -sharpe_ratio # Minimize negative Sharpe Ratio for maximization\n", "\n", "\n", "\n", "def optimize_portfolio(returns, risk_free_rate):\n", " \"\"\"\n", " Optimize portfolio to maximize the Sharpe Ratio.\n", "\n", " Args:\n", " - returns: pandas DataFrame, historical returns of assets\n", " - risk_free_rate: float, risk-free rate of return\n", "\n", " Returns:\n", " - array, optimal weights of assets in the portfolio\n", " \"\"\"\n", " num_assets = len(returns.columns)\n", " initial_weights = np.array([1 / num_assets] * num_assets)\n", " bounds = [(0, 1)] * num_assets # Bounds for asset weights (0 <= weight <= 1)\n", " constraints = ({'type': 'eq', 'fun': lambda weights: np.sum(weights) - 1}) # Sum of weights equals 1 constraint\n", "\n", " optimized_result = minimize(sharpe_ratio, initial_weights, args=(returns, risk_free_rate),\n", " method='SLSQP', bounds=bounds, constraints=constraints)\n", "\n", " return optimized_result.x" ] }, { "cell_type": "code", "execution_count": 33, "id": "ebf6b6bf", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "TATAPOWER.NS : 0.0\n", "TATAMOTORS.NS : 0.236548217499089\n", "TATASTEEL.NS : 0.17568900379556238\n", "ZOMATO.NS : 0.07826482194498546\n", "NHPC.NS : 0.21116461887342103\n", "NCC.NS : 0.0\n", "IREDA.NS : 0.0\n", "IRCON.NS : 0.2983333378869751\n" ] } ], "source": [ "optimal_weights = optimize_portfolio(equity_data, risk_free_rate)\n", "for i,j in zip(equity_list, optimal_weights):\n", " print(i, \" : \", j)" ] }, { "cell_type": "code", "execution_count": null, "id": "2a5e7bdf", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "3a6c6060", "metadata": {}, "source": [ "## STEPS FOR IMPLEMENTING\n", "\n", " 1) IMPORTING THE LIBRARIES\n", " 2) TWEETS EXTRACTION FROM STOCKNET\n", " 3) TWITTER DATA PRE-PROCESSING\n", " 4) ZERO-SHOT SENTIMENT CLASSIFICATION\n", " 5) FEATURE ENGINEERING OF TWEETS SENTIMENT VALUES\n", " 5.1) Number of Tweets for each individual days\n", " 5.2) Average of Emotion for each individual days\n", " 5.3) Median of Sentiment for each Single Day\n", " 5.4) Maximum Sentiment Value for each Single day\n", " 5.5) Minimum Sentiment Value for Each Single Day\n", " 5.6) Combining all the dataframes\n", " 6) STOCK DATA FROM STOCKNET\n", " 7) STOCK DATA AND FEATURE ENGINEERED SENTIMENT VALUES MERGING STEP\n", " 9) WITH SENTIMENT\n", " 9.1) DATASET PREPARATION FOR TRAINING\n", " 9.2) TRAINING\n", " 9.3) EVALUATING\n", " 9.4) GRAPHS AND METRICS" ] }, { "cell_type": "code", "execution_count": null, "id": "e4137507", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.10.13" } }, "nbformat": 4, "nbformat_minor": 5 }