Last active 2 months ago

Entry and exit signals with a sample (generic) python script

acedanger's Avatar acedanger revised this gist 2 months ago. Go to revision

No changes

acedanger's Avatar acedanger revised this gist 2 months ago. Go to revision

2 files changed, 23 insertions, 24 deletions

stock-entry-exit-technical-signals.md(file created)

@@ -0,0 +1,22 @@
1 + For entering positions, I'd focus on a combination of these technical indicators:
2 +
3 + **For Entry Signals:**
4 +
5 + - **Moving Average Crossovers** - When a shorter-term MA (like 20-day) crosses above a longer-term MA (like 50-day), it can signal upward momentum
6 + - **RSI (Relative Strength Index)** - Looking for oversold conditions (RSI below 30) that might indicate a bounce opportunity
7 + - **MACD** - When the MACD line crosses above the signal line, especially after being in negative territory
8 + - **Volume confirmation** - Ensuring any breakout or signal is accompanied by higher-than-average volume
9 + - **Support and Resistance levels** - Entering near strong support levels or after a clean breakout above resistance
10 +
11 + **For Exit Signals:**
12 +
13 + - **Trailing stops** based on ATR (Average True Range) to let winners run while protecting against major reversals
14 + - **RSI overbought conditions** (above 70) combined with bearish divergence
15 + - **Moving average violations** - When price closes below a key moving average that previously provided support
16 + - **MACD bearish crossover** - When MACD crosses below the signal line
17 + - **Volume patterns** - Selling into high volume spikes, especially if accompanied by reversal candlestick patterns
18 + - **Predetermined risk/reward ratios** - Taking profits at 2:1 or 3:1 reward-to-risk levels
19 +
20 + The key is using multiple indicators together rather than relying on any single one, and always having a clear exit plan before entering any position. Volume confirmation is crucial for validating most technical signals.
21 +
22 +

gistfile1.txt renamed to technical-analysis.py

@@ -1,25 +1,3 @@
1 - For entering positions, I'd focus on a combination of these technical indicators:
2 -
3 - **For Entry Signals:**
4 -
5 - - **Moving Average Crossovers** - When a shorter-term MA (like 20-day) crosses above a longer-term MA (like 50-day), it can signal upward momentum
6 - - **RSI (Relative Strength Index)** - Looking for oversold conditions (RSI below 30) that might indicate a bounce opportunity
7 - - **MACD** - When the MACD line crosses above the signal line, especially after being in negative territory
8 - - **Volume confirmation** - Ensuring any breakout or signal is accompanied by higher-than-average volume
9 - - **Support and Resistance levels** - Entering near strong support levels or after a clean breakout above resistance
10 -
11 - **For Exit Signals:**
12 -
13 - - **Trailing stops** based on ATR (Average True Range) to let winners run while protecting against major reversals
14 - - **RSI overbought conditions** (above 70) combined with bearish divergence
15 - - **Moving average violations** - When price closes below a key moving average that previously provided support
16 - - **MACD bearish crossover** - When MACD crosses below the signal line
17 - - **Volume patterns** - Selling into high volume spikes, especially if accompanied by reversal candlestick patterns
18 - - **Predetermined risk/reward ratios** - Taking profits at 2:1 or 3:1 reward-to-risk levels
19 -
20 - The key is using multiple indicators together rather than relying on any single one, and always having a clear exit plan before entering any position. Volume confirmation is crucial for validating most technical signals.
21 -
22 - ```python
23 1 import pandas as pd
24 2 import numpy as np
25 3 from datetime import datetime, timedelta
@@ -340,5 +318,4 @@ if __name__ == "__main__":
340 318 print("2. Adjust indicator parameters based on your trading style")
341 319 print("3. Modify signal thresholds based on backtesting results")
342 320 print("4. Always combine with risk management and position sizing")
343 - print("5. Consider market conditions and fundamental analysis")
344 - ```
321 + print("5. Consider market conditions and fundamental analysis")

acedanger's Avatar acedanger revised this gist 2 months ago. Go to revision

1 file changed, 344 insertions

gistfile1.txt(file created)

@@ -0,0 +1,344 @@
1 + For entering positions, I'd focus on a combination of these technical indicators:
2 +
3 + **For Entry Signals:**
4 +
5 + - **Moving Average Crossovers** - When a shorter-term MA (like 20-day) crosses above a longer-term MA (like 50-day), it can signal upward momentum
6 + - **RSI (Relative Strength Index)** - Looking for oversold conditions (RSI below 30) that might indicate a bounce opportunity
7 + - **MACD** - When the MACD line crosses above the signal line, especially after being in negative territory
8 + - **Volume confirmation** - Ensuring any breakout or signal is accompanied by higher-than-average volume
9 + - **Support and Resistance levels** - Entering near strong support levels or after a clean breakout above resistance
10 +
11 + **For Exit Signals:**
12 +
13 + - **Trailing stops** based on ATR (Average True Range) to let winners run while protecting against major reversals
14 + - **RSI overbought conditions** (above 70) combined with bearish divergence
15 + - **Moving average violations** - When price closes below a key moving average that previously provided support
16 + - **MACD bearish crossover** - When MACD crosses below the signal line
17 + - **Volume patterns** - Selling into high volume spikes, especially if accompanied by reversal candlestick patterns
18 + - **Predetermined risk/reward ratios** - Taking profits at 2:1 or 3:1 reward-to-risk levels
19 +
20 + The key is using multiple indicators together rather than relying on any single one, and always having a clear exit plan before entering any position. Volume confirmation is crucial for validating most technical signals.
21 +
22 + ```python
23 + import pandas as pd
24 + import numpy as np
25 + from datetime import datetime, timedelta
26 + import warnings
27 + warnings.filterwarnings('ignore')
28 +
29 + class TechnicalAnalyzer:
30 + def __init__(self, data):
31 + """
32 + Initialize with price data DataFrame
33 + Expected columns: ['date', 'open', 'high', 'low', 'close', 'volume']
34 + """
35 + self.data = data.copy()
36 + self.signals = pd.DataFrame()
37 +
38 + def calculate_sma(self, period):
39 + """Simple Moving Average"""
40 + return self.data['close'].rolling(window=period).mean()
41 +
42 + def calculate_ema(self, period):
43 + """Exponential Moving Average"""
44 + return self.data['close'].ewm(span=period).mean()
45 +
46 + def calculate_rsi(self, period=14):
47 + """Relative Strength Index"""
48 + delta = self.data['close'].diff()
49 + gain = (delta.where(delta > 0, 0)).rolling(window=period).mean()
50 + loss = (-delta.where(delta < 0, 0)).rolling(window=period).mean()
51 + rs = gain / loss
52 + rsi = 100 - (100 / (1 + rs))
53 + return rsi
54 +
55 + def calculate_macd(self, fast=12, slow=26, signal=9):
56 + """MACD Indicator"""
57 + ema_fast = self.calculate_ema(fast)
58 + ema_slow = self.calculate_ema(slow)
59 + macd_line = ema_fast - ema_slow
60 + signal_line = macd_line.ewm(span=signal).mean()
61 + histogram = macd_line - signal_line
62 + return macd_line, signal_line, histogram
63 +
64 + def calculate_bollinger_bands(self, period=20, std_dev=2):
65 + """Bollinger Bands"""
66 + sma = self.calculate_sma(period)
67 + std = self.data['close'].rolling(window=period).std()
68 + upper_band = sma + (std * std_dev)
69 + lower_band = sma - (std * std_dev)
70 + return upper_band, sma, lower_band
71 +
72 + def calculate_atr(self, period=14):
73 + """Average True Range"""
74 + high_low = self.data['high'] - self.data['low']
75 + high_close = np.abs(self.data['high'] - self.data['close'].shift())
76 + low_close = np.abs(self.data['low'] - self.data['close'].shift())
77 + ranges = pd.concat([high_low, high_close, low_close], axis=1)
78 + true_range = np.max(ranges, axis=1)
79 + atr = true_range.rolling(window=period).mean()
80 + return atr
81 +
82 + def calculate_volume_indicators(self):
83 + """Volume-based indicators"""
84 + # Volume Moving Average
85 + vol_sma_20 = self.data['volume'].rolling(window=20).mean()
86 + vol_ratio = self.data['volume'] / vol_sma_20
87 +
88 + # On Balance Volume (OBV)
89 + obv = (np.sign(self.data['close'].diff()) * self.data['volume']).fillna(0).cumsum()
90 +
91 + return vol_ratio, obv
92 +
93 + def generate_all_indicators(self):
94 + """Calculate all technical indicators"""
95 + # Moving Averages
96 + self.data['sma_20'] = self.calculate_sma(20)
97 + self.data['sma_50'] = self.calculate_sma(50)
98 + self.data['ema_12'] = self.calculate_ema(12)
99 + self.data['ema_26'] = self.calculate_ema(26)
100 +
101 + # RSI
102 + self.data['rsi'] = self.calculate_rsi()
103 +
104 + # MACD
105 + macd, signal, histogram = self.calculate_macd()
106 + self.data['macd'] = macd
107 + self.data['macd_signal'] = signal
108 + self.data['macd_histogram'] = histogram
109 +
110 + # Bollinger Bands
111 + bb_upper, bb_middle, bb_lower = self.calculate_bollinger_bands()
112 + self.data['bb_upper'] = bb_upper
113 + self.data['bb_middle'] = bb_middle
114 + self.data['bb_lower'] = bb_lower
115 +
116 + # ATR
117 + self.data['atr'] = self.calculate_atr()
118 +
119 + # Volume indicators
120 + vol_ratio, obv = self.calculate_volume_indicators()
121 + self.data['vol_ratio'] = vol_ratio
122 + self.data['obv'] = obv
123 +
124 + return self.data
125 +
126 + def identify_entry_signals(self):
127 + """Identify potential entry points"""
128 + signals = []
129 +
130 + for i in range(1, len(self.data)):
131 + entry_score = 0
132 + reasons = []
133 +
134 + current = self.data.iloc[i]
135 + previous = self.data.iloc[i-1]
136 +
137 + # Moving Average Crossover (Golden Cross)
138 + if (current['sma_20'] > current['sma_50'] and
139 + previous['sma_20'] <= previous['sma_50']):
140 + entry_score += 2
141 + reasons.append("SMA Golden Cross")
142 +
143 + # Price above both MAs
144 + if current['close'] > current['sma_20'] > current['sma_50']:
145 + entry_score += 1
146 + reasons.append("Price above MAs")
147 +
148 + # RSI oversold recovery
149 + if previous['rsi'] < 30 and current['rsi'] > 30:
150 + entry_score += 2
151 + reasons.append("RSI oversold recovery")
152 +
153 + # MACD bullish crossover
154 + if (current['macd'] > current['macd_signal'] and
155 + previous['macd'] <= previous['macd_signal']):
156 + entry_score += 2
157 + reasons.append("MACD bullish crossover")
158 +
159 + # Bollinger Band bounce
160 + if previous['close'] <= previous['bb_lower'] and current['close'] > previous['bb_lower']:
161 + entry_score += 1
162 + reasons.append("BB lower band bounce")
163 +
164 + # Volume confirmation
165 + if current['vol_ratio'] > 1.5: # 50% above average
166 + entry_score += 1
167 + reasons.append("High volume")
168 +
169 + # Strong overall conditions
170 + if (current['rsi'] > 40 and current['rsi'] < 70 and
171 + current['macd'] > 0):
172 + entry_score += 1
173 + reasons.append("Favorable momentum")
174 +
175 + if entry_score >= 3: # Minimum threshold for entry
176 + signals.append({
177 + 'date': current['date'],
178 + 'type': 'ENTRY',
179 + 'price': current['close'],
180 + 'score': entry_score,
181 + 'reasons': reasons
182 + })
183 +
184 + return signals
185 +
186 + def identify_exit_signals(self):
187 + """Identify potential exit points"""
188 + signals = []
189 +
190 + for i in range(1, len(self.data)):
191 + exit_score = 0
192 + reasons = []
193 +
194 + current = self.data.iloc[i]
195 + previous = self.data.iloc[i-1]
196 +
197 + # Moving Average bearish cross
198 + if (current['sma_20'] < current['sma_50'] and
199 + previous['sma_20'] >= previous['sma_50']):
200 + exit_score += 2
201 + reasons.append("SMA Death Cross")
202 +
203 + # Price below key MA
204 + if current['close'] < current['sma_20']:
205 + exit_score += 1
206 + reasons.append("Price below SMA20")
207 +
208 + # RSI overbought
209 + if current['rsi'] > 70:
210 + exit_score += 1
211 + reasons.append("RSI overbought")
212 +
213 + # RSI bearish divergence (simplified)
214 + if previous['rsi'] > 70 and current['rsi'] < 70:
215 + exit_score += 2
216 + reasons.append("RSI overbought exit")
217 +
218 + # MACD bearish crossover
219 + if (current['macd'] < current['macd_signal'] and
220 + previous['macd'] >= previous['macd_signal']):
221 + exit_score += 2
222 + reasons.append("MACD bearish crossover")
223 +
224 + # Bollinger Band upper touch
225 + if current['close'] >= current['bb_upper']:
226 + exit_score += 1
227 + reasons.append("BB upper band resistance")
228 +
229 + # Volume spike (could indicate distribution)
230 + if current['vol_ratio'] > 3.0:
231 + exit_score += 1
232 + reasons.append("Extreme volume spike")
233 +
234 + if exit_score >= 3: # Minimum threshold for exit
235 + signals.append({
236 + 'date': current['date'],
237 + 'type': 'EXIT',
238 + 'price': current['close'],
239 + 'score': exit_score,
240 + 'reasons': reasons
241 + })
242 +
243 + return signals
244 +
245 + def analyze_stock(self):
246 + """Complete analysis workflow"""
247 + # Generate all indicators
248 + self.generate_all_indicators()
249 +
250 + # Get entry and exit signals
251 + entry_signals = self.identify_entry_signals()
252 + exit_signals = self.identify_exit_signals()
253 +
254 + # Combine all signals
255 + all_signals = entry_signals + exit_signals
256 + all_signals = sorted(all_signals, key=lambda x: x['date'])
257 +
258 + return all_signals, self.data
259 +
260 + # Example usage and demo data generation
261 + def generate_sample_data(days=252):
262 + """Generate sample stock data for demonstration"""
263 + np.random.seed(42) # For reproducible results
264 +
265 + start_date = datetime.now() - timedelta(days=days)
266 + dates = [start_date + timedelta(days=i) for i in range(days)]
267 +
268 + # Generate realistic price movement
269 + returns = np.random.normal(0.001, 0.02, days) # Daily returns
270 + price = 100 # Starting price
271 + prices = [price]
272 +
273 + for ret in returns[1:]:
274 + price *= (1 + ret)
275 + prices.append(price)
276 +
277 + # Generate OHLC data
278 + data = []
279 + for i, (date, close) in enumerate(zip(dates, prices)):
280 + high = close * (1 + abs(np.random.normal(0, 0.015)))
281 + low = close * (1 - abs(np.random.normal(0, 0.015)))
282 + open_price = low + (high - low) * np.random.random()
283 + volume = int(np.random.normal(1000000, 300000))
284 +
285 + data.append({
286 + 'date': date,
287 + 'open': open_price,
288 + 'high': high,
289 + 'low': low,
290 + 'close': close,
291 + 'volume': max(volume, 100000) # Ensure positive volume
292 + })
293 +
294 + return pd.DataFrame(data)
295 +
296 + # Demo execution
297 + if __name__ == "__main__":
298 + # Generate sample data
299 + print("Generating sample stock data...")
300 + sample_data = generate_sample_data(180) # 6 months of data
301 +
302 + # Initialize analyzer
303 + analyzer = TechnicalAnalyzer(sample_data)
304 +
305 + # Run complete analysis
306 + print("Analyzing technical indicators...")
307 + signals, enhanced_data = analyzer.analyze_stock()
308 +
309 + # Display results
310 + print(f"\n=== TECHNICAL ANALYSIS RESULTS ===")
311 + print(f"Analysis period: {len(sample_data)} days")
312 + print(f"Total signals found: {len(signals)}")
313 +
314 + # Show recent indicators
315 + print(f"\n=== LATEST INDICATOR VALUES ===")
316 + latest = enhanced_data.iloc[-1]
317 + print(f"Price: ${latest['close']:.2f}")
318 + print(f"RSI: {latest['rsi']:.2f}")
319 + print(f"MACD: {latest['macd']:.4f}")
320 + print(f"Volume Ratio: {latest['vol_ratio']:.2f}x")
321 + print(f"20-day SMA: ${latest['sma_20']:.2f}")
322 + print(f"50-day SMA: ${latest['sma_50']:.2f}")
323 +
324 + # Show recent signals
325 + print(f"\n=== RECENT SIGNALS ===")
326 + recent_signals = [s for s in signals if s['date'] >= (datetime.now() - timedelta(days=30))]
327 +
328 + if recent_signals:
329 + for signal in recent_signals[-5:]: # Last 5 signals
330 + print(f"\n{signal['type']} Signal:")
331 + print(f" Date: {signal['date'].strftime('%Y-%m-%d')}")
332 + print(f" Price: ${signal['price']:.2f}")
333 + print(f" Score: {signal['score']}")
334 + print(f" Reasons: {', '.join(signal['reasons'])}")
335 + else:
336 + print("No recent signals found.")
337 +
338 + print(f"\n=== USAGE NOTES ===")
339 + print("1. Replace sample data with real market data from your preferred source")
340 + print("2. Adjust indicator parameters based on your trading style")
341 + print("3. Modify signal thresholds based on backtesting results")
342 + print("4. Always combine with risk management and position sizing")
343 + print("5. Consider market conditions and fundamental analysis")
344 + ```
Newer Older