refactor: restructure repository and add README, CLAUDE.md, LICENSE
- Move utility scripts to scripts/ (check_market, check_positions, etc.) - Move test files to tests/ (test_modules, test_mt5_connection, etc.) - Move deprecated dashboards to archive/ - Move research files to docs/research/ - Add sys.path fix to all moved Python files - Rewrite README.md with architecture diagram and badges - Add CLAUDE.md project guide - Add MIT LICENSE - Update .gitignore with archive/ pattern Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
"""Quick market analysis script"""
|
||||
# Run from project root: python scripts/check_market.py
|
||||
import sys, os
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from dotenv import load_dotenv
|
||||
load_dotenv()
|
||||
|
||||
from src.mt5_connector import MT5Connector
|
||||
from src.smc_polars import SMCAnalyzer
|
||||
from src.config import TradingConfig
|
||||
|
||||
config = TradingConfig()
|
||||
mt5 = MT5Connector(config.mt5_login, config.mt5_password, config.mt5_server, config.mt5_path)
|
||||
mt5.connect()
|
||||
|
||||
# Get data
|
||||
df = mt5.get_market_data('XAUUSD', 'M15', 500)
|
||||
print('=== MARKET DATA ===')
|
||||
print(f'Candles: {len(df)}')
|
||||
print(f'Last close: {df["close"].tail(1).item():.2f}')
|
||||
|
||||
# Current price
|
||||
tick = mt5.get_tick('XAUUSD')
|
||||
print(f'Bid: {tick.bid:.2f}, Ask: {tick.ask:.2f}')
|
||||
print(f'Spread: {(tick.ask - tick.bid):.2f}')
|
||||
|
||||
# SMC Analysis
|
||||
smc = SMCAnalyzer()
|
||||
df_smc = smc.calculate_all(df)
|
||||
|
||||
# Check last 20 candles for SMC patterns
|
||||
print('')
|
||||
print('=== SMC PATTERNS (Last 20 candles) ===')
|
||||
last_20 = df_smc.tail(20).select(['time', 'close', 'bos', 'choch', 'is_fvg_bull', 'is_fvg_bear', 'ob', 'fvg_signal', 'market_structure']).to_dicts()
|
||||
|
||||
pattern_found = False
|
||||
for i, row in enumerate(last_20):
|
||||
markers = []
|
||||
if row.get('bos', 0) != 0:
|
||||
markers.append(f'BOS={row["bos"]}')
|
||||
if row.get('choch', 0) != 0:
|
||||
markers.append(f'CHoCH={row["choch"]}')
|
||||
if row.get('is_fvg_bull'):
|
||||
markers.append('FVG_BULL')
|
||||
if row.get('is_fvg_bear'):
|
||||
markers.append('FVG_BEAR')
|
||||
if row.get('ob', 0) > 0:
|
||||
markers.append('OB_BULL')
|
||||
if row.get('ob', 0) < 0:
|
||||
markers.append('OB_BEAR')
|
||||
|
||||
if markers:
|
||||
pattern_found = True
|
||||
print(f' [{i}] {row["close"]:.2f} | {" | ".join(markers)}')
|
||||
|
||||
if not pattern_found:
|
||||
print(' No patterns in last 20 candles!')
|
||||
|
||||
# Generate signal
|
||||
signal = smc.generate_signal(df_smc)
|
||||
print('')
|
||||
print('=== SMC SIGNAL RESULT ===')
|
||||
if signal:
|
||||
print(f'Signal: {signal.signal_type}')
|
||||
print(f'Entry: {signal.entry_price:.2f}')
|
||||
print(f'SL: {signal.stop_loss:.2f}')
|
||||
print(f'TP: {signal.take_profit:.2f}')
|
||||
print(f'Confidence: {signal.confidence:.0%}')
|
||||
print(f'Reason: {signal.reason}')
|
||||
else:
|
||||
print('Signal: NONE - No valid setup')
|
||||
|
||||
# Check last 5 candles
|
||||
print('')
|
||||
print('Last 5 candles detail:')
|
||||
last_5 = df_smc.tail(5).to_dicts()
|
||||
for i, row in enumerate(last_5):
|
||||
print(f' [{i}] Close={row["close"]:.2f}, BOS={row.get("bos",0)}, CHoCH={row.get("choch",0)}, FVG_B={row.get("is_fvg_bull",False)}, FVG_S={row.get("is_fvg_bear",False)}, OB={row.get("ob",0)}')
|
||||
|
||||
# Check overall SMC stats
|
||||
print('')
|
||||
print('=== SMC STATISTICS (All 500 candles) ===')
|
||||
bos_bull = df_smc.filter(df_smc['bos'] > 0).height
|
||||
bos_bear = df_smc.filter(df_smc['bos'] < 0).height
|
||||
choch_bull = df_smc.filter(df_smc['choch'] > 0).height
|
||||
choch_bear = df_smc.filter(df_smc['choch'] < 0).height
|
||||
fvg_bull = df_smc.filter(df_smc['is_fvg_bull'] == True).height
|
||||
fvg_bear = df_smc.filter(df_smc['is_fvg_bear'] == True).height
|
||||
ob_bull = df_smc.filter(df_smc['ob'] > 0).height
|
||||
ob_bear = df_smc.filter(df_smc['ob'] < 0).height
|
||||
|
||||
print(f'BOS Bullish: {bos_bull}, BOS Bearish: {bos_bear}')
|
||||
print(f'CHoCH Bullish: {choch_bull}, CHoCH Bearish: {choch_bear}')
|
||||
print(f'FVG Bullish: {fvg_bull}, FVG Bearish: {fvg_bear}')
|
||||
print(f'OB Bullish: {ob_bull}, OB Bearish: {ob_bear}')
|
||||
|
||||
# Check when was the last BOS/CHoCH
|
||||
print('')
|
||||
print('=== LAST STRUCTURE BREAKS ===')
|
||||
bos_indices = df_smc.with_row_index().filter(df_smc['bos'] != 0).select(['index', 'time', 'close', 'bos']).tail(3).to_dicts()
|
||||
choch_indices = df_smc.with_row_index().filter(df_smc['choch'] != 0).select(['index', 'time', 'close', 'choch']).tail(3).to_dicts()
|
||||
|
||||
print('Last 3 BOS:')
|
||||
for row in bos_indices:
|
||||
candles_ago = 499 - row['index']
|
||||
print(f' {row["time"]} | Close={row["close"]:.2f} | BOS={row["bos"]} | {candles_ago} candles ago')
|
||||
|
||||
print('Last 3 CHoCH:')
|
||||
for row in choch_indices:
|
||||
candles_ago = 499 - row['index']
|
||||
print(f' {row["time"]} | Close={row["close"]:.2f} | CHoCH={row["choch"]} | {candles_ago} candles ago')
|
||||
|
||||
mt5.disconnect()
|
||||
@@ -0,0 +1,59 @@
|
||||
"""Check open positions and account status."""
|
||||
# Run from project root: python scripts/check_positions.py
|
||||
import sys, os
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from dotenv import load_dotenv
|
||||
load_dotenv()
|
||||
|
||||
import MetaTrader5 as mt5
|
||||
|
||||
# Connect
|
||||
mt5.initialize(
|
||||
login=int(os.getenv("MT5_LOGIN")),
|
||||
password=os.getenv("MT5_PASSWORD"),
|
||||
server=os.getenv("MT5_SERVER"),
|
||||
path=os.getenv("MT5_PATH"),
|
||||
)
|
||||
|
||||
# Account info
|
||||
account = mt5.account_info()
|
||||
print("=" * 50)
|
||||
print("ACCOUNT STATUS")
|
||||
print("=" * 50)
|
||||
print(f"Balance: ${account.balance:,.2f}")
|
||||
print(f"Equity: ${account.equity:,.2f}")
|
||||
print(f"Margin: ${account.margin:,.2f}")
|
||||
print(f"Free Margin: ${account.margin_free:,.2f}")
|
||||
print(f"Profit: ${account.profit:,.2f}")
|
||||
print(f"Leverage: 1:{account.leverage}")
|
||||
|
||||
# Open positions
|
||||
print("\n" + "=" * 50)
|
||||
print("OPEN POSITIONS")
|
||||
print("=" * 50)
|
||||
positions = mt5.positions_get()
|
||||
if positions:
|
||||
for pos in positions:
|
||||
print(f"#{pos.ticket} | {'BUY' if pos.type == 0 else 'SELL'} {pos.volume} {pos.symbol}")
|
||||
print(f" Open: {pos.price_open:.2f} | Current: {pos.price_current:.2f}")
|
||||
print(f" SL: {pos.sl:.2f} | TP: {pos.tp:.2f}")
|
||||
print(f" Profit: ${pos.profit:,.2f}")
|
||||
print()
|
||||
else:
|
||||
print("No open positions")
|
||||
|
||||
# Recent history
|
||||
print("=" * 50)
|
||||
print("RECENT DEALS (Last 10)")
|
||||
print("=" * 50)
|
||||
from datetime import datetime, timedelta
|
||||
deals = mt5.history_deals_get(datetime.now() - timedelta(days=1), datetime.now())
|
||||
if deals:
|
||||
for deal in deals[-10:]:
|
||||
deal_type = "BUY" if deal.type == 0 else "SELL" if deal.type == 1 else "OTHER"
|
||||
print(f"#{deal.ticket} | {deal_type} {deal.volume} @ {deal.price:.2f} | Profit: ${deal.profit:,.2f}")
|
||||
else:
|
||||
print("No recent deals")
|
||||
|
||||
mt5.shutdown()
|
||||
@@ -0,0 +1,52 @@
|
||||
"""Quick status check script."""
|
||||
# Run from project root: python scripts/check_status.py
|
||||
import sys, os
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
import MetaTrader5 as mt5
|
||||
from dotenv import load_dotenv
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
load_dotenv()
|
||||
|
||||
mt5.initialize()
|
||||
mt5.login(
|
||||
int(os.getenv('MT5_LOGIN')),
|
||||
os.getenv('MT5_PASSWORD'),
|
||||
os.getenv('MT5_SERVER')
|
||||
)
|
||||
|
||||
# Account info
|
||||
info = mt5.account_info()
|
||||
print('='*50)
|
||||
print('ACCOUNT STATUS')
|
||||
print('='*50)
|
||||
print(f'Balance: ${info.balance:,.2f}')
|
||||
print(f'Equity: ${info.equity:,.2f}')
|
||||
print(f'Profit: ${info.profit:,.2f}')
|
||||
print(f'Margin: ${info.margin:,.2f}')
|
||||
|
||||
# Open positions
|
||||
positions = mt5.positions_get(symbol='XAUUSD')
|
||||
print(f'\nOpen Positions: {len(positions) if positions else 0}')
|
||||
if positions:
|
||||
total_profit = 0
|
||||
for pos in positions:
|
||||
total_profit += pos.profit
|
||||
ptype = "BUY" if pos.type==0 else "SELL"
|
||||
print(f' #{pos.ticket}: {ptype} {pos.volume} @ {pos.price_open:.2f} | P/L: ${pos.profit:.2f}')
|
||||
print(f' Total Floating: ${total_profit:.2f}')
|
||||
|
||||
# Recent closed trades
|
||||
history = mt5.history_deals_get(datetime.now() - timedelta(days=1), datetime.now())
|
||||
if history:
|
||||
closed_trades = [d for d in history if d.profit != 0]
|
||||
print(f'\nClosed Trades (24h): {len(closed_trades)}')
|
||||
total_closed = 0
|
||||
for deal in closed_trades[-10:]:
|
||||
total_closed += deal.profit
|
||||
result = "WIN" if deal.profit > 0 else "LOSS"
|
||||
print(f' #{deal.ticket}: {deal.symbol} ${deal.profit:+.2f} [{result}]')
|
||||
print(f' Total Closed P/L: ${total_closed:+.2f}')
|
||||
|
||||
mt5.shutdown()
|
||||
@@ -0,0 +1,58 @@
|
||||
"""Close all open positions."""
|
||||
# Run from project root: python scripts/close_positions.py
|
||||
import sys, os
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from dotenv import load_dotenv
|
||||
load_dotenv()
|
||||
|
||||
import MetaTrader5 as mt5
|
||||
|
||||
# Connect
|
||||
mt5.initialize(
|
||||
login=int(os.getenv("MT5_LOGIN")),
|
||||
password=os.getenv("MT5_PASSWORD"),
|
||||
server=os.getenv("MT5_SERVER"),
|
||||
path=os.getenv("MT5_PATH"),
|
||||
)
|
||||
|
||||
# Get open positions
|
||||
positions = mt5.positions_get()
|
||||
if positions:
|
||||
for pos in positions:
|
||||
print(f"\nClosing #{pos.ticket} | {'BUY' if pos.type == 0 else 'SELL'} {pos.volume} {pos.symbol}")
|
||||
print(f" Open: {pos.price_open:.2f} | Current: {pos.price_current:.2f}")
|
||||
print(f" Profit: ${pos.profit:,.2f}")
|
||||
|
||||
# Close position
|
||||
tick = mt5.symbol_info_tick(pos.symbol)
|
||||
close_price = tick.bid if pos.type == 0 else tick.ask
|
||||
|
||||
request = {
|
||||
"action": mt5.TRADE_ACTION_DEAL,
|
||||
"symbol": pos.symbol,
|
||||
"volume": pos.volume,
|
||||
"type": mt5.ORDER_TYPE_SELL if pos.type == 0 else mt5.ORDER_TYPE_BUY,
|
||||
"position": pos.ticket,
|
||||
"price": close_price,
|
||||
"deviation": 20,
|
||||
"magic": 123456,
|
||||
"comment": "Manual close",
|
||||
"type_time": mt5.ORDER_TIME_GTC,
|
||||
}
|
||||
|
||||
result = mt5.order_send(request)
|
||||
if result.retcode == mt5.TRADE_RETCODE_DONE:
|
||||
print(f" CLOSED successfully! Profit: ${pos.profit:,.2f}")
|
||||
else:
|
||||
print(f" Failed to close: {result.comment} (code: {result.retcode})")
|
||||
else:
|
||||
print("No open positions")
|
||||
|
||||
# Check final balance
|
||||
account = mt5.account_info()
|
||||
print(f"\n{'='*50}")
|
||||
print(f"Final Balance: ${account.balance:,.2f}")
|
||||
print(f"Final Equity: ${account.equity:,.2f}")
|
||||
|
||||
mt5.shutdown()
|
||||
@@ -0,0 +1,100 @@
|
||||
"""Get real trading history from MT5."""
|
||||
# Run from project root: python scripts/get_trade_history.py
|
||||
import sys, os
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
from dotenv import load_dotenv
|
||||
load_dotenv()
|
||||
|
||||
import MetaTrader5 as mt5
|
||||
|
||||
if not mt5.initialize():
|
||||
print('MT5 init failed')
|
||||
exit()
|
||||
|
||||
if not mt5.login(int(os.getenv('MT5_LOGIN')), os.getenv('MT5_PASSWORD'), os.getenv('MT5_SERVER')):
|
||||
print('MT5 login failed')
|
||||
exit()
|
||||
|
||||
# Get account info
|
||||
account = mt5.account_info()
|
||||
print(f'Account: {account.login}')
|
||||
print(f'Balance: ${account.balance:,.2f}')
|
||||
print(f'Equity: ${account.equity:,.2f}')
|
||||
print()
|
||||
|
||||
# Get trade history (last 14 days)
|
||||
from_date = datetime.now() - timedelta(days=14)
|
||||
to_date = datetime.now() + timedelta(days=1)
|
||||
|
||||
deals = mt5.history_deals_get(from_date, to_date)
|
||||
print(f'Total deals in last 14 days: {len(deals) if deals else 0}')
|
||||
print()
|
||||
|
||||
if deals:
|
||||
# Group by position to calculate trade results
|
||||
trades = {}
|
||||
for deal in deals:
|
||||
if deal.position_id > 0:
|
||||
if deal.position_id not in trades:
|
||||
trades[deal.position_id] = []
|
||||
trades[deal.position_id].append(deal)
|
||||
|
||||
print('=' * 70)
|
||||
print('REAL TRADING HISTORY (Last 14 days)')
|
||||
print('=' * 70)
|
||||
|
||||
total_profit = 0
|
||||
wins = 0
|
||||
losses = 0
|
||||
trade_list = []
|
||||
|
||||
for pos_id, pos_deals in trades.items():
|
||||
if len(pos_deals) >= 2:
|
||||
# Has entry and exit
|
||||
entry = next((d for d in pos_deals if d.entry == 0), None) # DEAL_ENTRY_IN
|
||||
exit_deal = next((d for d in pos_deals if d.entry == 1), None) # DEAL_ENTRY_OUT
|
||||
|
||||
if entry and exit_deal:
|
||||
profit = exit_deal.profit
|
||||
direction = 'BUY' if entry.type == 0 else 'SELL'
|
||||
entry_time = datetime.fromtimestamp(entry.time)
|
||||
exit_time = datetime.fromtimestamp(exit_deal.time)
|
||||
|
||||
result = 'WIN' if profit > 0 else 'LOSS'
|
||||
if profit > 0:
|
||||
wins += 1
|
||||
else:
|
||||
losses += 1
|
||||
total_profit += profit
|
||||
|
||||
trade_list.append({
|
||||
'time': entry_time,
|
||||
'direction': direction,
|
||||
'lot': entry.volume,
|
||||
'profit': profit,
|
||||
'result': result
|
||||
})
|
||||
|
||||
# Sort by time and print
|
||||
trade_list.sort(key=lambda x: x['time'])
|
||||
for t in trade_list[-50:]: # Last 50 trades
|
||||
print(f" {t['time']} | {t['direction']} | Lot: {t['lot']} | ${t['profit']:+.2f} [{t['result']}]")
|
||||
|
||||
print()
|
||||
print('=' * 70)
|
||||
print('REAL TRADING SUMMARY')
|
||||
print('=' * 70)
|
||||
total_trades = wins + losses
|
||||
win_rate = (wins / total_trades * 100) if total_trades > 0 else 0
|
||||
avg_profit = total_profit / total_trades if total_trades > 0 else 0
|
||||
|
||||
print(f' Total Trades : {total_trades}')
|
||||
print(f' Winning Trades : {wins}')
|
||||
print(f' Losing Trades : {losses}')
|
||||
print(f' Win Rate : {win_rate:.1f}%')
|
||||
print(f' Total P/L : ${total_profit:+,.2f}')
|
||||
print(f' Average/Trade : ${avg_profit:+.2f}')
|
||||
|
||||
mt5.shutdown()
|
||||
@@ -0,0 +1,60 @@
|
||||
"""Modify TP of open positions to closer targets."""
|
||||
# Run from project root: python scripts/modify_tp.py
|
||||
import sys, os
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from dotenv import load_dotenv
|
||||
load_dotenv()
|
||||
|
||||
import MetaTrader5 as mt5
|
||||
|
||||
# Connect
|
||||
mt5.initialize(
|
||||
login=int(os.getenv("MT5_LOGIN")),
|
||||
password=os.getenv("MT5_PASSWORD"),
|
||||
server=os.getenv("MT5_SERVER"),
|
||||
path=os.getenv("MT5_PATH"),
|
||||
)
|
||||
|
||||
# Get current tick
|
||||
tick = mt5.symbol_info_tick("XAUUSD")
|
||||
current_price = tick.bid
|
||||
print(f"Current price: {current_price:.2f}")
|
||||
|
||||
# Get open positions
|
||||
positions = mt5.positions_get()
|
||||
if positions:
|
||||
for pos in positions:
|
||||
print(f"\n#{pos.ticket} | {'BUY' if pos.type == 0 else 'SELL'} {pos.volume} {pos.symbol}")
|
||||
print(f" Open: {pos.price_open:.2f} | Current: {pos.price_current:.2f}")
|
||||
print(f" Current SL: {pos.sl:.2f} | Current TP: {pos.tp:.2f}")
|
||||
print(f" Profit: ${pos.profit:,.2f}")
|
||||
|
||||
# Set TP 5 points above current to lock in profits
|
||||
if pos.type == 0: # BUY
|
||||
new_tp = current_price + 5 # 5 points above current for quick TP
|
||||
new_sl = pos.price_open - 10 # Tighter stop loss (protect profit)
|
||||
else: # SELL
|
||||
new_tp = current_price - 5
|
||||
new_sl = pos.price_open + 10
|
||||
|
||||
print(f" New SL: {new_sl:.2f} | New TP: {new_tp:.2f}")
|
||||
|
||||
# Modify position
|
||||
request = {
|
||||
"action": mt5.TRADE_ACTION_SLTP,
|
||||
"symbol": pos.symbol,
|
||||
"position": pos.ticket,
|
||||
"sl": new_sl,
|
||||
"tp": new_tp,
|
||||
}
|
||||
|
||||
result = mt5.order_send(request)
|
||||
if result.retcode == mt5.TRADE_RETCODE_DONE:
|
||||
print(f" MODIFIED successfully!")
|
||||
else:
|
||||
print(f" Failed to modify: {result.comment} (code: {result.retcode})")
|
||||
else:
|
||||
print("No open positions")
|
||||
|
||||
mt5.shutdown()
|
||||
Reference in New Issue
Block a user