-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtrader.py
More file actions
executable file
·204 lines (167 loc) · 7.75 KB
/
trader.py
File metadata and controls
executable file
·204 lines (167 loc) · 7.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
#!/usr/bin/env python3
"""
Trade Engine - Main Entry Point
Automated trading system with Zerodha Kite and Telegram integration
"""
import sys
import time
from datetime import datetime
import config
from src.state_manager import load_state, save_state, reset_position
from src.telegram_client import TelegramClient
from src.broker import ZerodhaBroker
from src.strategy import TechnicalStrategy
def main():
# Validate command line arguments
if len(sys.argv) != 2:
print("Usage: python trader.py <TICKER>")
print("Example: python trader.py RELIANCE")
sys.exit(1)
SYMBOL = sys.argv[1].upper()
# Initialize components
print(f"Initializing Trade Engine for {SYMBOL}...")
state = load_state(config.STATE_FILE)
telegram = TelegramClient(config.TELEGRAM_BOT_TOKEN, config.TELEGRAM_CHAT_ID)
broker = ZerodhaBroker(config.API_KEY, config.ACCESS_TOKEN, config.EXCHANGE)
strategy = TechnicalStrategy(
broker=broker,
interval=config.INTERVAL,
ema_short=config.EMA_SHORT,
ema_long=config.EMA_LONG,
rsi_period=config.RSI_PERIOD,
rsi_threshold=config.RSI_THRESHOLD
)
# Get instrument token
token = broker.get_instrument_token(SYMBOL)
if token is None:
print(f"ERROR: Could not find instrument token for {SYMBOL}")
sys.exit(1)
# Send startup notification
telegram.send_message(f"🤖 Trade Engine started for {SYMBOL}")
print(f"✓ Trade Engine running for {SYMBOL}")
print(f"✓ Check interval: {config.CHECK_INTERVAL_SECONDS}s")
print(f"✓ Telegram notifications enabled")
print("-" * 50)
# Main trading loop
while True:
try:
current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
print(f"\n[{current_time}] Analyzing {SYMBOL}...")
# Analyze market conditions
candle, strong_trend, indicators = strategy.analyze(token, state)
if candle is None:
print("⚠ Could not fetch market data, retrying...")
time.sleep(config.ERROR_RETRY_SECONDS)
continue
# Determine recommendation
recommendation = "HOLD"
if strong_trend and state["position"] == "NONE":
recommendation = "BUY"
elif state["position"] == "LONG" and not strong_trend:
recommendation = "SELL"
print(f"Position: {state['position']} | Recommendation: {recommendation}")
print(f"Close: {candle['close']:.2f} | RSI: {indicators['rsi']:.2f} | EMA20: {indicators['ema20']:.2f}")
# Send analysis to Telegram
telegram.send_analysis(SYMBOL, recommendation, indicators)
# Check for manual override from Telegram
user_command = telegram.read_latest_reply(state)
save_state(state, config.STATE_FILE) # Save updated last_update_id
# Execute trades based on user command or recommendation
if user_command == "BUY":
if state["buy_count"] < config.MAX_PYRAMID_BUYS:
execute_buy(SYMBOL, broker, telegram, state, candle, indicators)
else:
telegram.send_message(f"⚠ Max pyramid buys ({config.MAX_PYRAMID_BUYS}) reached")
elif user_command == "SELL":
if state["position"] == "LONG":
execute_sell(SYMBOL, broker, telegram, state, candle)
else:
telegram.send_message("⚠ No position to sell")
elif user_command == "STATUS":
send_status(telegram, state, SYMBOL)
# Auto-trade based on recommendation (optional, can be disabled)
# Uncomment the following lines to enable auto-trading
# elif recommendation == "BUY" and state["buy_count"] < config.MAX_PYRAMID_BUYS:
# execute_buy(SYMBOL, broker, telegram, state, candle, indicators)
# elif recommendation == "SELL" and state["position"] == "LONG":
# execute_sell(SYMBOL, broker, telegram, state, candle)
print(f"Waiting {config.CHECK_INTERVAL_SECONDS}s for next check...")
time.sleep(config.CHECK_INTERVAL_SECONDS)
except KeyboardInterrupt:
print("\n\nShutting down Trade Engine...")
telegram.send_message(f"🛑 Trade Engine stopped for {SYMBOL}")
save_state(state, config.STATE_FILE)
sys.exit(0)
except Exception as e:
error_msg = f"❌ Error: {str(e)}"
print(error_msg)
telegram.send_message(error_msg)
time.sleep(config.ERROR_RETRY_SECONDS)
def execute_buy(symbol: str, broker, telegram, state, candle, indicators):
"""Execute buy order and update state"""
try:
ltp = broker.get_ltp(symbol)
if ltp is None:
telegram.send_message("⚠ Could not fetch LTP for buy order")
return
order_id = broker.place_buy_order(symbol, 1, config.PRODUCT_TYPE)
if order_id:
state["buy_count"] += 1
state["position"] = "LONG"
state["qty"] = state.get("qty", 0) + 1
# Update average price
old_total = state.get("avg_price", 0) * (state["qty"] - 1)
state["avg_price"] = (old_total + ltp) / state["qty"]
# Calculate stop loss
atr = indicators.get("atr", ltp * 0.02) # Default 2% if ATR unavailable
state["sl"] = ltp - (atr * 1.5)
save_state(state, config.STATE_FILE)
telegram.send_trade_alert(symbol, "BUY", ltp, 1)
telegram.send_message(f"✅ Order ID: {order_id}\nSL: ₹{state['sl']:.2f}")
print(f"✓ BUY executed at ₹{ltp:.2f}")
else:
telegram.send_message("❌ Buy order failed")
except Exception as e:
telegram.send_message(f"❌ Buy error: {e}")
def execute_sell(symbol: str, broker, telegram, state, candle):
"""Execute sell order and update state"""
try:
ltp = broker.get_ltp(symbol)
if ltp is None:
telegram.send_message("⚠ Could not fetch LTP for sell order")
return
qty = state.get("qty", 0)
order_id = broker.place_sell_order(symbol, qty, config.PRODUCT_TYPE)
if order_id:
# Calculate P&L
pnl = (ltp - state["avg_price"]) * qty
pnl_pct = (pnl / (state["avg_price"] * qty)) * 100
telegram.send_trade_alert(symbol, "SELL", ltp, qty)
telegram.send_message(
f"✅ Order ID: {order_id}\n"
f"P&L: ₹{pnl:.2f} ({pnl_pct:+.2f}%)\n"
f"Entry: ₹{state['avg_price']:.2f} | Exit: ₹{ltp:.2f}"
)
print(f"✓ SELL executed at ₹{ltp:.2f} | P&L: ₹{pnl:.2f}")
reset_position(state)
save_state(state, config.STATE_FILE)
else:
telegram.send_message("❌ Sell order failed")
except Exception as e:
telegram.send_message(f"❌ Sell error: {e}")
def send_status(telegram, state, symbol):
"""Send current position status"""
if state["position"] == "NONE":
telegram.send_message(f"📊 {symbol}\nNo active position")
else:
message = f"""
📊 {symbol} Status
Position: {state['position']}
Quantity: {state['qty']}
Avg Price: ₹{state['avg_price']:.2f}
Stop Loss: ₹{state['sl']:.2f}
Buy Count: {state['buy_count']}/{config.MAX_PYRAMID_BUYS}
""".strip()
telegram.send_message(message)
if __name__ == "__main__":
main()