Skip to content

Commit 112cf2c

Browse files
committed
backtesting rsi+ma
1 parent a961287 commit 112cf2c

File tree

7 files changed

+3603
-3
lines changed

7 files changed

+3603
-3
lines changed

Untitled1.ipynb

Lines changed: 2531 additions & 0 deletions
Large diffs are not rendered by default.

backtesting-donchian-channel.ipynb

Lines changed: 2 additions & 2 deletions
Large diffs are not rendered by default.

backtesting.ipynb

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,30 @@
3030
"- https://github.com/facundoallia?tab=repositories"
3131
]
3232
},
33+
{
34+
"cell_type": "markdown",
35+
"id": "cd5772e8-fbee-48fc-922e-8391bef7b709",
36+
"metadata": {},
37+
"source": [
38+
"### Backtesting SMA / MA"
39+
]
40+
},
41+
{
42+
"cell_type": "markdown",
43+
"id": "b8438441-b69a-4119-b857-f0ed9b2ce90b",
44+
"metadata": {},
45+
"source": [
46+
"- https://medium.com/coinmonks/3-simple-moving-averages-trade-strategy-performance-test-2194f423d36b\n",
47+
"- https://datasciencedrivein.medium.com/three-way-moving-average-trading-strategy-no-short-selling-required-w-python-code-1a7940a46ac1\n",
48+
"- https://intrinio.medium.com/how-to-quickly-construct-and-backtest-a-simple-moving-average-crossover-strategy-with-python-cf9d0431a16c\n",
49+
"- https://readmedium.com/en/https:/medium.com/swlh/backtesting-algorithmic-trading-strategies-in-5-simple-steps-python-e2f19e231930\n",
50+
"- https://github.com/peiyingchin/Medium/blob/main/Back%20test%20your%20Simple%20moving%20average%20(SMA)%20strategy%20in%20stock%20using%20Python/SMA%20strategy-MRO.ipynb"
51+
]
52+
},
3353
{
3454
"cell_type": "code",
3555
"execution_count": null,
36-
"id": "d8af3253-62c0-4211-9fe3-779249a4d636",
56+
"id": "6fed0024-02a4-4443-a2a8-7e979e8453cd",
3757
"metadata": {},
3858
"outputs": [],
3959
"source": []

historical-prices.ipynb

Lines changed: 560 additions & 0 deletions
Large diffs are not rendered by default.

plotting-MA.ipynb

Lines changed: 323 additions & 0 deletions
Large diffs are not rendered by default.

screener-02.ipynb

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"id": "fb4c77e0-f8b7-47fa-b514-35c5161ee7ca",
6+
"metadata": {},
7+
"source": [
8+
"# Screener 02\n",
9+
"\n",
10+
"https://readmedium.com/en/https:/wire.insiderfinance.io/identifying-breakout-stocks-with-python-a-data-driven-selection-guide-d8a3d1ba172e\n",
11+
"https://github.com/shashankvemuri/Finance/blob/master/find_stocks/get_rsi_tickers.py\n",
12+
"\n",
13+
"https://medium.com/@redeaddiscolll\n",
14+
"https://medium.com/@py.chin315\n",
15+
"https://github.com/peiyingchin/Medium/blob/main/Trading%20strategy%20with%2055%25%20win%20chance/Trading%20strategy%20with%2055%25%20win%20chance.ipynb"
16+
]
17+
},
18+
{
19+
"cell_type": "code",
20+
"execution_count": 2,
21+
"id": "00beccde-3951-4426-a338-29a19777f853",
22+
"metadata": {},
23+
"outputs": [
24+
{
25+
"ename": "KeyError",
26+
"evalue": "['Target Price', 'P/E']",
27+
"output_type": "error",
28+
"traceback": [
29+
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
30+
"\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)",
31+
"\u001b[0;32m/tmp/ipykernel_27437/3637564337.py\u001b[0m in \u001b[0;36m?\u001b[0;34m()\u001b[0m\n\u001b[1;32m 27\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mtop_candidates\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'Ticker'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'Company'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'Sector'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'Industry'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'Price'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'Volume'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'P/E'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'Target Price'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'Price to Target %'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'Composite Score'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 28\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 29\u001b[0m \u001b[0;31m# Usage of the function with the path to the CSV file\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 30\u001b[0m \u001b[0mcsv_file_path\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m'nifty50_symbols.txt'\u001b[0m \u001b[0;31m# Replace with your actual file path\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 31\u001b[0;31m \u001b[0mselected_stocks\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mselect_breakout_candidates\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcsv_file_path\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 32\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 33\u001b[0m \u001b[0;31m# Display the selected stocks\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 34\u001b[0m \u001b[0mselected_stocks\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
32+
"\u001b[0;32m/tmp/ipykernel_27437/3637564337.py\u001b[0m in \u001b[0;36m?\u001b[0;34m(csv_path)\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;31m# Load the dataset\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 6\u001b[0m \u001b[0mstock_data\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mpd\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mread_csv\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcsv_path\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 7\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 8\u001b[0m \u001b[0;31m# Preprocessing and filtering based on the provided criteria\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 9\u001b[0;31m \u001b[0mstock_data_filtered\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mstock_data\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdropna\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msubset\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'Target Price'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'P/E'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 10\u001b[0m \u001b[0mstock_data_filtered\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mstock_data_filtered\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mstock_data_filtered\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'Price'\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m<\u001b[0m \u001b[0mstock_data_filtered\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'Target Price'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 11\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 12\u001b[0m \u001b[0;31m# Calculate additional metrics\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
33+
"\u001b[0;32m~/stock-market/env3/lib/python3.10/site-packages/pandas/core/frame.py\u001b[0m in \u001b[0;36m?\u001b[0;34m(self, axis, how, thresh, subset, inplace, ignore_index)\u001b[0m\n\u001b[1;32m 6414\u001b[0m \u001b[0max\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_get_axis\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0magg_axis\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 6415\u001b[0m \u001b[0mindices\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0max\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_indexer_for\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msubset\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 6416\u001b[0m \u001b[0mcheck\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mindices\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m-\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 6417\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mcheck\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0many\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 6418\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mKeyError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0marray\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msubset\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mcheck\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtolist\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 6419\u001b[0m \u001b[0magg_obj\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtake\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mindices\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0maxis\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0magg_axis\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 6420\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 6421\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mthresh\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mlib\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mno_default\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
34+
"\u001b[0;31mKeyError\u001b[0m: ['Target Price', 'P/E']"
35+
]
36+
}
37+
],
38+
"source": [
39+
"import pandas as pd\n",
40+
"\n",
41+
"# Define the function to load data and select breakout stock candidates\n",
42+
"def select_breakout_candidates(csv_path):\n",
43+
" # Load the dataset\n",
44+
" stock_data = pd.read_csv(csv_path)\n",
45+
" \n",
46+
" # Preprocessing and filtering based on the provided criteria\n",
47+
" stock_data_filtered = stock_data.dropna(subset=['Target Price', 'P/E'])\n",
48+
" stock_data_filtered = stock_data_filtered[stock_data_filtered['Price'] < stock_data_filtered['Target Price']]\n",
49+
" \n",
50+
" # Calculate additional metrics\n",
51+
" stock_data_filtered['Price to Target %'] = ((stock_data_filtered['Target Price'] - stock_data_filtered['Price']) / stock_data_filtered['Price']) * 100\n",
52+
" stock_data_filtered['Change Percentile'] = stock_data_filtered['Change'].rank(pct=True)\n",
53+
" stock_data_filtered['Volume Percentile'] = stock_data_filtered['Volume'].rank(pct=True)\n",
54+
" stock_data_filtered['Price to Target Percentile'] = stock_data_filtered['Price to Target %'].rank(pct=True)\n",
55+
" stock_data_filtered['Composite Score'] = stock_data_filtered[['Change Percentile', 'Volume Percentile', 'Price to Target Percentile']].mean(axis=1)\n",
56+
" \n",
57+
" # Exclude overvalued stocks based on P/E ratio threshold\n",
58+
" pe_threshold = stock_data_filtered['P/E'].quantile(0.80)\n",
59+
" candidates = stock_data_filtered[stock_data_filtered['P/E'] <= pe_threshold]\n",
60+
" \n",
61+
" # Select top candidates based on composite score\n",
62+
" top_candidates = candidates.sort_values(by='Composite Score', ascending=False).head(8)\n",
63+
" \n",
64+
" # Return the selection with relevant information for the article\n",
65+
" return top_candidates[['Ticker', 'Company', 'Sector', 'Industry', 'Price', 'Volume', 'P/E', 'Target Price', 'Price to Target %', 'Composite Score']]\n",
66+
"\n",
67+
"# Usage of the function with the path to the CSV file\n",
68+
"csv_file_path = 'nifty50_symbols.txt' # Replace with your actual file path\n",
69+
"selected_stocks = select_breakout_candidates(csv_file_path)\n",
70+
"\n",
71+
"# Display the selected stocks\n",
72+
"selected_stocks"
73+
]
74+
},
75+
{
76+
"cell_type": "markdown",
77+
"id": "37410db1-243b-4ee7-8b04-e89389d3b0ec",
78+
"metadata": {},
79+
"source": [
80+
"## RSI"
81+
]
82+
},
83+
{
84+
"cell_type": "code",
85+
"execution_count": null,
86+
"id": "0e7dd783-c120-4588-94bb-3ff8ddc3a575",
87+
"metadata": {},
88+
"outputs": [],
89+
"source": [
90+
"# Import Dependencies\n",
91+
"import datetime\n",
92+
"from pandas_datareader import data as pdr\n",
93+
"import sys\n",
94+
"import os\n",
95+
"parent_dir = os.path.dirname(os.getcwd())\n",
96+
"sys.path.append(parent_dir)\n",
97+
"import ta_functions as ta\n",
98+
"import tickers as ti\n",
99+
"\n",
100+
"# Get dates for the past year\n",
101+
"start_date = datetime.datetime.now() - datetime.timedelta(days=365)\n",
102+
"end_date = datetime.date.today()\n",
103+
"\n",
104+
"# Load list of S&P 500 tickers from tickers module\n",
105+
"tickers = ti.tickers_sp500()\n",
106+
"\n",
107+
"# Initialize lists for overbought and oversold tickers\n",
108+
"oversold_tickers = []\n",
109+
"overbought_tickers = []\n",
110+
"\n",
111+
"# Retrieve adjusted close prices for the tickers\n",
112+
"sp500_data = pdr.get_data_yahoo(tickers, start_date, end_date)['Adj Close']\n",
113+
"\n",
114+
"# Analyze each ticker for RSI\n",
115+
"for ticker in tickers:\n",
116+
" try:\n",
117+
" # Create a new DataFrame for the ticker\n",
118+
" data = sp500_data[[ticker]].copy()\n",
119+
"\n",
120+
" # Calculate the RSI for the ticker\n",
121+
" data[\"rsi\"] = ta.RSI(data[ticker], timeperiod=14)\n",
122+
"\n",
123+
" # Calculate the mean of the last 14 RSI values\n",
124+
" mean_rsi = data[\"rsi\"].tail(14).mean()\n",
125+
"\n",
126+
" # Print the RSI value\n",
127+
" print(f'{ticker} has an RSI value of {round(mean_rsi, 2)}')\n",
128+
"\n",
129+
" # Classify the ticker based on its RSI value\n",
130+
" if mean_rsi <= 30:\n",
131+
" oversold_tickers.append(ticker)\n",
132+
" elif mean_rsi >= 70:\n",
133+
" overbought_tickers.append(ticker)\n",
134+
"\n",
135+
" except Exception as e:\n",
136+
" print(f'Error processing {ticker}: {e}')\n",
137+
"\n",
138+
"# Output the lists of oversold and overbought tickers\n",
139+
"print(f'Oversold tickers: {oversold_tickers}')\n",
140+
"print(f'Overbought tickers: {overbought_tickers}')"
141+
]
142+
}
143+
],
144+
"metadata": {
145+
"kernelspec": {
146+
"display_name": "Python 3 (ipykernel)",
147+
"language": "python",
148+
"name": "python3"
149+
},
150+
"language_info": {
151+
"codemirror_mode": {
152+
"name": "ipython",
153+
"version": 3
154+
},
155+
"file_extension": ".py",
156+
"mimetype": "text/x-python",
157+
"name": "python",
158+
"nbconvert_exporter": "python",
159+
"pygments_lexer": "ipython3",
160+
"version": "3.10.12"
161+
}
162+
},
163+
"nbformat": 4,
164+
"nbformat_minor": 5
165+
}

us-data.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
['MMM' 'AOS' 'ABT' 'ABBV' 'ACN' 'ADBE' 'AMD' 'AES' 'AFL' 'A' 'APD' 'ABNB']

0 commit comments

Comments
 (0)