| name | trading-automation-skill |
| description | Master automated trading systems and EA development for all platforms. Use for MetaTrader EA (MQL4/MQL5 Expert Advisors), TradingView Pine Script strategies, Python trading bots (Backtrader, CCXT, TA-Lib), cTrader cAlgo (C#), backtesting frameworks, strategy optimization, position sizing algorithms, order management systems, VPS deployment, multi-platform automation, error handling, monitoring dashboards, and production-ready trading robots for Forex, Crypto, and Stocks markets.. Also use for Thai keywords "เทรด", "ซื้อขาย", "การเทรด", "trading", "อัตโนมัติ", "ทำให้อัตโนมัติ", "automation", "ลดขั้นตอน", "เขียนโค้ด", "โปรแกรม", "พัฒนา", "coding", "programming" |
🤖 Trading Automation Mastery Skill
Master automated trading systems across all major platforms
Platforms: MetaTrader 4/5 | TradingView | Python | cTrader
Markets: Forex | Crypto | Stocks | All Markets
📚 Table of Contents
- MetaTrader Expert Advisors (MQL4/MQL5)
- TradingView Pine Script Strategies
- Python Trading Bots
- cTrader Automation (cAlgo)
- Backtesting Frameworks
- Strategy Optimization
- Order Management Systems
- Risk Management Integration
- VPS Deployment & Monitoring
- Production Best Practices
1. MetaTrader Expert Advisors (MQL4/MQL5) {#metatrader-expert-advisors}
🎯 EA Structure (MQL4)
//+------------------------------------------------------------------+
//| Simple_EA.mq4 |
//| Professional EA Template |
//+------------------------------------------------------------------+
// Input Parameters
input double LotSize = 0.01; // Position size
input int StopLoss = 50; // Stop loss in pips
input int TakeProfit = 100; // Take profit in pips
input int MagicNumber = 12345; // Unique identifier
input int Slippage = 3; // Maximum slippage
// Global Variables
double point;
int ticket = 0;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
// Calculate point value (4-digit vs 5-digit brokers)
if(Digits == 3 || Digits == 5)
point = Point * 10;
else
point = Point;
Print("EA Initialized successfully");
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
Print("EA removed: ", reason);
}
//+------------------------------------------------------------------+
//| Expert tick function (called on every price change) |
//+------------------------------------------------------------------+
void OnTick()
{
// Check if we already have an open position
if(CountOrders() > 0)
return;
// Entry Logic
if(BuySignal())
{
OpenBuyOrder();
}
else if(SellSignal())
{
OpenSellOrder();
}
}
//+------------------------------------------------------------------+
//| Count open orders with our MagicNumber |
//+------------------------------------------------------------------+
int CountOrders()
{
int count = 0;
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
count++;
}
}
return count;
}
//+------------------------------------------------------------------+
//| Buy Signal Logic (Example: Simple MA Crossover) |
//+------------------------------------------------------------------+
bool BuySignal()
{
double ma_fast = iMA(NULL, 0, 10, 0, MODE_SMA, PRICE_CLOSE, 0);
double ma_slow = iMA(NULL, 0, 20, 0, MODE_SMA, PRICE_CLOSE, 0);
double ma_fast_prev = iMA(NULL, 0, 10, 0, MODE_SMA, PRICE_CLOSE, 1);
double ma_slow_prev = iMA(NULL, 0, 20, 0, MODE_SMA, PRICE_CLOSE, 1);
// Crossover: Fast MA crosses above Slow MA
if(ma_fast > ma_slow && ma_fast_prev <= ma_slow_prev)
return true;
return false;
}
//+------------------------------------------------------------------+
//| Sell Signal Logic |
//+------------------------------------------------------------------+
bool SellSignal()
{
double ma_fast = iMA(NULL, 0, 10, 0, MODE_SMA, PRICE_CLOSE, 0);
double ma_slow = iMA(NULL, 0, 20, 0, MODE_SMA, PRICE_CLOSE, 0);
double ma_fast_prev = iMA(NULL, 0, 10, 0, MODE_SMA, PRICE_CLOSE, 1);
double ma_slow_prev = iMA(NULL, 0, 20, 0, MODE_SMA, PRICE_CLOSE, 1);
// Crossunder: Fast MA crosses below Slow MA
if(ma_fast < ma_slow && ma_fast_prev >= ma_slow_prev)
return true;
return false;
}
//+------------------------------------------------------------------+
//| Open Buy Order |
//+------------------------------------------------------------------+
void OpenBuyOrder()
{
double entry = Ask;
double sl = entry - StopLoss * point;
double tp = entry + TakeProfit * point;
ticket = OrderSend(Symbol(), OP_BUY, LotSize, entry, Slippage, sl, tp,
"Buy Order", MagicNumber, 0, clrGreen);
if(ticket > 0)
Print("Buy order opened: #", ticket);
else
Print("Error opening buy order: ", GetLastError());
}
//+------------------------------------------------------------------+
//| Open Sell Order |
//+------------------------------------------------------------------+
void OpenSellOrder()
{
double entry = Bid;
double sl = entry + StopLoss * point;
double tp = entry - TakeProfit * point;
ticket = OrderSend(Symbol(), OP_SELL, LotSize, entry, Slippage, sl, tp,
"Sell Order", MagicNumber, 0, clrRed);
if(ticket > 0)
Print("Sell order opened: #", ticket);
else
Print("Error opening sell order: ", GetLastError());
}
🎯 Advanced EA Features (MQL5)
//+------------------------------------------------------------------+
//| Advanced_EA.mq5 |
//| Multi-timeframe, Trailing Stop |
//+------------------------------------------------------------------+
#include <Trade\Trade.mqh>
CTrade trade;
// Input Parameters
input double RiskPercent = 2.0; // Risk per trade (%)
input int ATR_Period = 14; // ATR period
input double ATR_StopLoss = 2.0; // SL = ATR × this multiplier
input double ATR_TakeProfit = 3.0; // TP = ATR × this multiplier
input int TrailingStop = 50; // Trailing stop in points
input bool UseTrailing = true; // Enable trailing stop
//+------------------------------------------------------------------+
//| Expert initialization |
//+------------------------------------------------------------------+
int OnInit()
{
trade.SetExpertMagicNumber(123456);
trade.SetDeviationInPoints(10);
trade.SetTypeFilling(ORDER_FILLING_FOK);
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// Trailing stop management
if(UseTrailing)
ManageTrailingStop();
// Check for new entries (only on new bar)
if(!IsNewBar())
return;
// Entry logic
if(BuySignalMTF())
{
OpenBuyPosition();
}
else if(SellSignalMTF())
{
OpenSellPosition();
}
}
//+------------------------------------------------------------------+
//| Check if new bar formed |
//+------------------------------------------------------------------+
datetime lastBarTime = 0;
bool IsNewBar()
{
datetime currentBarTime = iTime(_Symbol, PERIOD_CURRENT, 0);
if(currentBarTime != lastBarTime)
{
lastBarTime = currentBarTime;
return true;
}
return false;
}
//+------------------------------------------------------------------+
//| Multi-timeframe Buy Signal |
//+------------------------------------------------------------------+
bool BuySignalMTF()
{
// Higher timeframe: Trend confirmation (H4)
double ma_h4 = iMA(_Symbol, PERIOD_H4, 50, 0, MODE_SMA, PRICE_CLOSE);
double close_h4 = iClose(_Symbol, PERIOD_H4, 0);
if(close_h4 < ma_h4)
return false; // Must be above H4 MA (uptrend)
// Current timeframe: Entry signal (M15)
double rsi = iRSI(_Symbol, PERIOD_CURRENT, 14, PRICE_CLOSE);
// RSI oversold + trending up on H4
if(rsi < 30)
return true;
return false;
}
//+------------------------------------------------------------------+
//| Multi-timeframe Sell Signal |
//+------------------------------------------------------------------+
bool SellSignalMTF()
{
// Higher timeframe: Trend confirmation (H4)
double ma_h4 = iMA(_Symbol, PERIOD_H4, 50, 0, MODE_SMA, PRICE_CLOSE);
double close_h4 = iClose(_Symbol, PERIOD_H4, 0);
if(close_h4 > ma_h4)
return false; // Must be below H4 MA (downtrend)
// Current timeframe: Entry signal (M15)
double rsi = iRSI(_Symbol, PERIOD_CURRENT, 14, PRICE_CLOSE);
// RSI overbought + trending down on H4
if(rsi > 70)
return true;
return false;
}
//+------------------------------------------------------------------+
//| Calculate position size based on risk % |
//+------------------------------------------------------------------+
double CalculateLotSize(double stopLossDistance)
{
double accountBalance = AccountInfoDouble(ACCOUNT_BALANCE);
double riskAmount = accountBalance * (RiskPercent / 100.0);
double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
double tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
double lotSize = (riskAmount * tickSize) / (stopLossDistance * tickValue);
// Round to allowed lot step
double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
double maxLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
double lotStep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
lotSize = MathFloor(lotSize / lotStep) * lotStep;
lotSize = MathMax(minLot, MathMin(maxLot, lotSize));
return lotSize;
}
//+------------------------------------------------------------------+
//| Open Buy Position with ATR-based SL/TP |
//+------------------------------------------------------------------+
void OpenBuyPosition()
{
double atr = iATR(_Symbol, PERIOD_CURRENT, ATR_Period);
double entry = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double sl = entry - (atr * ATR_StopLoss);
double tp = entry + (atr * ATR_TakeProfit);
double stopLossDistance = entry - sl;
double lotSize = CalculateLotSize(stopLossDistance);
if(trade.Buy(lotSize, _Symbol, entry, sl, tp, "ATR Buy"))
{
Print("Buy position opened: Lots=", lotSize, " SL=", sl, " TP=", tp);
}
else
{
Print("Error opening buy position: ", GetLastError());
}
}
//+------------------------------------------------------------------+
//| Open Sell Position with ATR-based SL/TP |
//+------------------------------------------------------------------+
void OpenSellPosition()
{
double atr = iATR(_Symbol, PERIOD_CURRENT, ATR_Period);
double entry = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double sl = entry + (atr * ATR_StopLoss);
double tp = entry - (atr * ATR_TakeProfit);
double stopLossDistance = sl - entry;
double lotSize = CalculateLotSize(stopLossDistance);
if(trade.Sell(lotSize, _Symbol, entry, sl, tp, "ATR Sell"))
{
Print("Sell position opened: Lots=", lotSize, " SL=", sl, " TP=", tp);
}
else
{
Print("Error opening sell position: ", GetLastError());
}
}
//+------------------------------------------------------------------+
//| Trailing Stop Management |
//+------------------------------------------------------------------+
void ManageTrailingStop()
{
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
if(PositionSelectByTicket(PositionGetTicket(i)))
{
if(PositionGetString(POSITION_SYMBOL) != _Symbol)
continue;
double positionOpenPrice = PositionGetDouble(POSITION_PRICE_OPEN);
double currentSL = PositionGetDouble(POSITION_SL);
double currentPrice = (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
? SymbolInfoDouble(_Symbol, SYMBOL_BID)
: SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
double trailDistance = TrailingStop * point;
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
{
// Buy position: Move SL up
double newSL = currentPrice - trailDistance;
if(newSL > currentSL && newSL > positionOpenPrice)
{
trade.PositionModify(PositionGetTicket(i), newSL, PositionGetDouble(POSITION_TP));
Print("Trailing stop updated for BUY: New SL=", newSL);
}
}
else if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
{
// Sell position: Move SL down
double newSL = currentPrice + trailDistance;
if(newSL < currentSL && newSL < positionOpenPrice)
{
trade.PositionModify(PositionGetTicket(i), newSL, PositionGetDouble(POSITION_TP));
Print("Trailing stop updated for SELL: New SL=", newSL);
}
}
}
}
}
2. TradingView Pine Script Strategies {#tradingview-pine-script}
🎯 Basic Strategy Template (Pine Script v5)
//@version=5
strategy("Simple MA Crossover Strategy",
overlay=true,
initial_capital=10000,
default_qty_type=strategy.percent_of_equity,
default_qty_value=100,
commission_type=strategy.commission.percent,
commission_value=0.1)
// Input Parameters
fastLength = input.int(10, "Fast MA Length", minval=1)
slowLength = input.int(20, "Slow MA Length", minval=1)
riskPercent = input.float(2.0, "Risk per Trade (%)", minval=0.1, maxval=10.0)
// Calculate Moving Averages
fastMA = ta.sma(close, fastLength)
slowMA = ta.sma(close, slowLength)
// Plot MAs
plot(fastMA, "Fast MA", color=color.blue, linewidth=2)
plot(slowMA, "Slow MA", color=color.red, linewidth=2)
// Entry Conditions
longCondition = ta.crossover(fastMA, slowMA)
shortCondition = ta.crossunder(fastMA, slowMA)
// Exit Conditions (example: opposite signal)
exitLongCondition = shortCondition
exitShortCondition = longCondition
// Execute Trades
if longCondition
strategy.entry("Long", strategy.long)
if shortCondition
strategy.entry("Short", strategy.short)
// Background color on signal
bgcolor(longCondition ? color.new(color.green, 90) : na)
bgcolor(shortCondition ? color.new(color.red, 90) : na)
🎯 Advanced Strategy with ATR-based Risk Management
//@version=5
strategy("Advanced ATR Strategy",
overlay=true,
initial_capital=10000,
default_qty_type=strategy.cash,
commission_type=strategy.commission.percent,
commission_value=0.1)
// ==================== INPUTS ====================
// Risk Management
riskPercent = input.float(2.0, "Risk Per Trade (%)", minval=0.1, maxval=10, group="Risk Management")
atrMultiplierSL = input.float(2.0, "ATR Multiplier for SL", minval=0.5, maxval=5, group="Risk Management")
atrMultiplierTP = input.float(3.0, "ATR Multiplier for TP", minval=0.5, maxval=10, group="Risk Management")
useTrailing = input.bool(true, "Use Trailing Stop", group="Risk Management")
trailATRMult = input.float(1.5, "Trailing Stop ATR Multiplier", minval=0.5, maxval=5, group="Risk Management")
// Strategy Parameters
atrPeriod = input.int(14, "ATR Period", minval=1, group="Indicators")
rsiPeriod = input.int(14, "RSI Period", minval=1, group="Indicators")
rsiOversold = input.int(30, "RSI Oversold", minval=1, maxval=50, group="Indicators")
rsiOverbought = input.int(70, "RSI Overbought", minval=50, maxval=100, group="Indicators")
// Higher Timeframe
htfTimeframe = input.timeframe("240", "Higher Timeframe", group="Multi-Timeframe")
htfMALength = input.int(50, "HTF MA Length", minval=1, group="Multi-Timeframe")
// ==================== INDICATORS ====================
// ATR for volatility-based stops
atr = ta.atr(atrPeriod)
// RSI for entry signals
rsi = ta.rsi(close, rsiPeriod)
// Higher timeframe trend filter
htfMA = request.security(syminfo.tickerid, htfTimeframe, ta.sma(close, htfMALength))
htfTrendUp = close > htfMA
htfTrendDown = close < htfMA
// ==================== ENTRY LOGIC ====================
// Long: RSI oversold + HTF uptrend
longCondition = ta.crossover(rsi, rsiOversold) and htfTrendUp
// Short: RSI overbought + HTF downtrend
shortCondition = ta.crossunder(rsi, rsiOverbought) and htfTrendDown
// ==================== POSITION SIZING ====================
calcPositionSize(stopDistance) =>
riskAmount = strategy.equity * (riskPercent / 100)
positionSize = riskAmount / stopDistance
positionSize
// ==================== TRADE EXECUTION ====================
if longCondition and strategy.position_size == 0
stopLoss = close - (atr * atrMultiplierSL)
takeProfit = close + (atr * atrMultiplierTP)
stopDistance = close - stopLoss
qty = calcPositionSize(stopDistance)
strategy.entry("Long", strategy.long, qty=qty)
strategy.exit("Exit Long", "Long", stop=stopLoss, limit=takeProfit)
// Draw entry lines
line.new(bar_index, close, bar_index + 10, close, color=color.blue, width=2)
line.new(bar_index, stopLoss, bar_index + 10, stopLoss, color=color.red, width=1, style=line.style_dashed)
line.new(bar_index, takeProfit, bar_index + 10, takeProfit, color=color.green, width=1, style=line.style_dashed)
if shortCondition and strategy.position_size == 0
stopLoss = close + (atr * atrMultiplierSL)
takeProfit = close - (atr * atrMultiplierTP)
stopDistance = stopLoss - close
qty = calcPositionSize(stopDistance)
strategy.entry("Short", strategy.short, qty=qty)
strategy.exit("Exit Short", "Short", stop=stopLoss, limit=takeProfit)
// Draw entry lines
line.new(bar_index, close, bar_index + 10, close, color=color.red, width=2)
line.new(bar_index, stopLoss, bar_index + 10, stopLoss, color=color.red, width=1, style=line.style_dashed)
line.new(bar_index, takeProfit, bar_index + 10, takeProfit, color=color.green, width=1, style=line.style_dashed)
// ==================== TRAILING STOP ====================
if useTrailing and strategy.position_size != 0
if strategy.position_size > 0 // Long position
trailStop = close - (atr * trailATRMult)
strategy.exit("Trail Long", "Long", stop=trailStop)
if strategy.position_size < 0 // Short position
trailStop = close + (atr * trailATRMult)
strategy.exit("Trail Short", "Short", stop=trailStop)
// ==================== VISUALIZATION ====================
// Plot HTF MA
plot(htfMA, "HTF MA", color=color.orange, linewidth=2)
// Plot RSI levels (on separate pane)
hline(rsiOversold, "Oversold", color=color.green, linestyle=hline.style_dashed)
hline(rsiOverbought, "Overbought", color=color.red, linestyle=hline.style_dashed)
// Background color for trend
bgcolor(htfTrendUp ? color.new(color.green, 95) : color.new(color.red, 95))
// Signal markers
plotshape(longCondition, "Long Signal", shape.triangleup, location.belowbar, color.green, size=size.small)
plotshape(shortCondition, "Short Signal", shape.triangledown, location.abovebar, color.red, size=size.small)
🎯 Webhook Integration for Automation
//@version=5
strategy("Webhook Strategy", overlay=true)
// ... (strategy logic) ...
// Generate webhook message
longMessage = '{"action": "buy", "symbol": "' + syminfo.ticker + '", "price": ' + str.tostring(close) + '}'
shortMessage = '{"action": "sell", "symbol": "' + syminfo.ticker + '", "price": ' + str.tostring(close) + '}'
if longCondition
strategy.entry("Long", strategy.long, alert_message=longMessage)
if shortCondition
strategy.entry("Short", strategy.short, alert_message=shortMessage)
// Create alert with webhook
// Alert Condition: strategy.position_size changes
// Message: {{strategy.order.alert_message}}
// Webhook URL: your-automation-server.com/webhook
3. Python Trading Bots {#python-trading-bots}
🎯 Backtrader Strategy Template
import backtrader as bt
import pandas as pd
from datetime import datetime
class SimpleMAStrategy(bt.Strategy):
"""
Simple Moving Average Crossover Strategy
"""
params = (
('fast_period', 10),
('slow_period', 20),
('risk_percent', 2.0), # Risk per trade
('stop_loss_pct', 2.0), # Stop loss %
('take_profit_pct', 4.0), # Take profit %
('printlog', True),
)
def __init__(self):
# Indicators
self.fast_ma = bt.indicators.SimpleMovingAverage(
self.data.close, period=self.params.fast_period)
self.slow_ma = bt.indicators.SimpleMovingAverage(
self.data.close, period=self.params.slow_period)
# Crossover signal
self.crossover = bt.indicators.CrossOver(self.fast_ma, self.slow_ma)
# Track orders
self.order = None
self.entry_price = None
self.stop_loss = None
self.take_profit = None
def log(self, txt, dt=None):
"""Logging function"""
if self.params.printlog:
dt = dt or self.datas[0].datetime.date(0)
print(f'{dt.isoformat()} {txt}')
def notify_order(self, order):
"""Handle order notifications"""
if order.status in [order.Submitted, order.Accepted]:
return
if order.status in [order.Completed]:
if order.isbuy():
self.log(f'BUY EXECUTED, Price: {order.executed.price:.2f}, '
f'Cost: {order.executed.value:.2f}, '
f'Comm: {order.executed.comm:.2f}')
self.entry_price = order.executed.price
elif order.issell():
self.log(f'SELL EXECUTED, Price: {order.executed.price:.2f}, '
f'Cost: {order.executed.value:.2f}, '
f'Comm: {order.executed.comm:.2f}')
elif order.status in [order.Canceled, order.Margin, order.Rejected]:
self.log('Order Canceled/Margin/Rejected')
self.order = None
def notify_trade(self, trade):
"""Handle trade notifications"""
if not trade.isclosed:
return
self.log(f'OPERATION PROFIT, GROSS: {trade.pnl:.2f}, NET: {trade.pnlcomm:.2f}')
def next(self):
"""Main strategy logic executed on each bar"""
# Check if order is pending
if self.order:
return
# Check if we are in the market
if not self.position:
# Long signal: Fast MA crosses above Slow MA
if self.crossover > 0:
# Calculate position size based on risk
risk_amount = self.broker.getvalue() * (self.params.risk_percent / 100)
stop_distance = self.data.close[0] * (self.params.stop_loss_pct / 100)
size = risk_amount / stop_distance
# Place buy order
self.log(f'BUY CREATE, Price: {self.data.close[0]:.2f}')
self.order = self.buy(size=size)
# Set stop loss and take profit levels
self.stop_loss = self.data.close[0] * (1 - self.params.stop_loss_pct / 100)
self.take_profit = self.data.close[0] * (1 + self.params.take_profit_pct / 100)
else:
# We are in a long position
# Exit on stop loss
if self.data.close[0] <= self.stop_loss:
self.log(f'STOP LOSS HIT, Price: {self.data.close[0]:.2f}')
self.order = self.sell(size=self.position.size)
# Exit on take profit
elif self.data.close[0] >= self.take_profit:
self.log(f'TAKE PROFIT HIT, Price: {self.data.close[0]:.2f}')
self.order = self.sell(size=self.position.size)
# Exit on opposite signal
elif self.crossover < 0:
self.log(f'SELL SIGNAL, Price: {self.data.close[0]:.2f}')
self.order = self.sell(size=self.position.size)
# ==================== Backtesting Setup ====================
if __name__ == '__main__':
# Create cerebro instance
cerebro = bt.Cerebro()
# Add strategy
cerebro.addstrategy(SimpleMAStrategy)
# Load data (example: CSV file)
data = bt.feeds.GenericCSVData(
dataname='EURUSD_H1.csv',
dtformat=('%Y-%m-%d %H:%M:%S'),
datetime=0,
open=1,
high=2,
low=3,
close=4,
volume=5,
openinterest=-1
)
# Add data to cerebro
cerebro.adddata(data)
# Set initial capital
cerebro.broker.setcash(10000.0)
# Set commission (0.1%)
cerebro.broker.setcommission(commission=0.001)
# Add analyzers
cerebro.addanalyzer(bt.analyzers.SharpeRatio, _name='sharpe')
cerebro.addanalyzer(bt.analyzers.DrawDown, _name='drawdown')
cerebro.addanalyzer(bt.analyzers.Returns, _name='returns')
cerebro.addanalyzer(bt.analyzers.TradeAnalyzer, _name='trades')
# Print starting conditions
print(f'Starting Portfolio Value: {cerebro.broker.getvalue():.2f}')
# Run backtest
results = cerebro.run()
strat = results[0]
# Print final result
print(f'Final Portfolio Value: {cerebro.broker.getvalue():.2f}')
# Print performance metrics
print('\n=== Performance Metrics ===')
print(f'Sharpe Ratio: {strat.analyzers.sharpe.get_analysis()["sharperatio"]:.2f}')
print(f'Max Drawdown: {strat.analyzers.drawdown.get_analysis()["max"]["drawdown"]:.2f}%')
print(f'Total Return: {strat.analyzers.returns.get_analysis()["rtot"]:.2%}')
# Trade statistics
trade_analysis = strat.analyzers.trades.get_analysis()
print(f'\nTotal Trades: {trade_analysis.total.closed}')
print(f'Won: {trade_analysis.won.total} | Lost: {trade_analysis.lost.total}')
print(f'Win Rate: {trade_analysis.won.total / trade_analysis.total.closed:.2%}')
# Plot results
cerebro.plot(style='candlestick')
🎯 Crypto Exchange Bot (CCXT + Binance)
import ccxt
import pandas as pd
import time
from datetime import datetime
class CryptoTradingBot:
"""
Automated crypto trading bot using CCXT
"""
def __init__(self, api_key, api_secret, symbol='BTC/USDT', timeframe='1h'):
"""Initialize bot with exchange credentials"""
self.exchange = ccxt.binance({
'apiKey': api_key,
'secret': api_secret,
'enableRateLimit': True,
'options': {
'defaultType': 'future', # 'spot' or 'future'
}
})
self.symbol = symbol
self.timeframe = timeframe
self.position = None
self.entry_price = None
def fetch_ohlcv(self, limit=100):
"""Fetch historical OHLCV data"""
try:
ohlcv = self.exchange.fetch_ohlcv(self.symbol, self.timeframe, limit=limit)
df = pd.DataFrame(ohlcv, columns=['timestamp', 'open', 'high', 'low', 'close', 'volume'])
df['timestamp'] = pd.to_datetime(df['timestamp'], unit='ms')
return df
except Exception as e:
print(f"Error fetching OHLCV: {e}")
return None
def calculate_indicators(self, df):
"""Calculate technical indicators"""
# Moving averages
df['ma_fast'] = df['close'].rolling(window=10).mean()
df['ma_slow'] = df['close'].rolling(window=20).mean()
# RSI
delta = df['close'].diff()
gain = (delta.where(delta > 0, 0)).rolling(window=14).mean()
loss = (-delta.where(delta < 0, 0)).rolling(window=14).mean()
rs = gain / loss
df['rsi'] = 100 - (100 / (1 + rs))
# ATR for stop loss
high_low = df['high'] - df['low']
high_close = (df['high'] - df['close'].shift()).abs()
low_close = (df['low'] - df['close'].shift()).abs()
ranges = pd.concat([high_low, high_close, low_close], axis=1)
true_range = ranges.max(axis=1)
df['atr'] = true_range.rolling(14).mean()
return df
def check_entry_signal(self, df):
"""Check for entry signals"""
last_row = df.iloc[-1]
prev_row = df.iloc[-2]
# Long signal: MA crossover + RSI confirmation
if (prev_row['ma_fast'] <= prev_row['ma_slow'] and
last_row['ma_fast'] > last_row['ma_slow'] and
last_row['rsi'] < 70):
return 'long'
# Short signal: MA crossunder + RSI confirmation
if (prev_row['ma_fast'] >= prev_row['ma_slow'] and
last_row['ma_fast'] < last_row['ma_slow'] and
last_row['rsi'] > 30):
return 'short'
return None
def calculate_position_size(self, risk_percent=2.0):
"""Calculate position size based on account balance and risk"""
try:
balance = self.exchange.fetch_balance()
usdt_balance = balance['USDT']['free']
risk_amount = usdt_balance * (risk_percent / 100)
# Get current price
ticker = self.exchange.fetch_ticker(self.symbol)
current_price = ticker['last']
# Calculate quantity (simplified, should use ATR for stop distance)
quantity = risk_amount / current_price
return quantity
except Exception as e:
print(f"Error calculating position size: {e}")
return 0
def place_market_order(self, side, quantity):
"""Place market order"""
try:
order = self.exchange.create_market_order(
symbol=self.symbol,
side=side, # 'buy' or 'sell'
amount=quantity
)
print(f"Order placed: {side} {quantity} {self.symbol}")
print(f"Order ID: {order['id']}")
return order
except Exception as e:
print(f"Error placing order: {e}")
return None
def set_stop_loss_take_profit(self, entry_price, side, atr_value):
"""Set stop loss and take profit orders"""
try:
# Calculate SL/TP levels
if side == 'long':
stop_loss = entry_price - (2 * atr_value)
take_profit = entry_price + (3 * atr_value)
sl_side = 'sell'
else: # short
stop_loss = entry_price + (2 * atr_value)
take_profit = entry_price - (3 * atr_value)
sl_side = 'buy'
# Place stop loss order
sl_order = self.exchange.create_order(
symbol=self.symbol,
type='stop_market',
side=sl_side,
amount=self.position['quantity'],
params={'stopPrice': stop_loss}
)
# Place take profit order
tp_order = self.exchange.create_order(
symbol=self.symbol,
type='take_profit_market',
side=sl_side,
amount=self.position['quantity'],
params={'stopPrice': take_profit}
)
print(f"SL set at: {stop_loss}")
print(f"TP set at: {take_profit}")
except Exception as e:
print(f"Error setting SL/TP: {e}")
def run(self):
"""Main bot loop"""
print(f"Starting bot for {self.symbol} on {self.timeframe} timeframe...")
while True:
try:
# Fetch latest data
df = self.fetch_ohlcv()
if df is None:
time.sleep(60)
continue
# Calculate indicators
df = self.calculate_indicators(df)
# Check current position
positions = self.exchange.fetch_positions([self.symbol])
current_position = None
for pos in positions:
if float(pos['contracts']) != 0:
current_position = pos
break
# If no position, check for entry signal
if current_position is None:
signal = self.check_entry_signal(df)
if signal:
print(f"\n{'='*50}")
print(f"{datetime.now()} - {signal.upper()} SIGNAL DETECTED!")
print(f"{'='*50}")
# Calculate position size
quantity = self.calculate_position_size(risk_percent=2.0)
if quantity > 0:
# Place order
side = 'buy' if signal == 'long' else 'sell'
order = self.place_market_order(side, quantity)
if order:
self.position = {
'side': signal,
'quantity': quantity,
'entry_price': order['price']
}
# Set SL/TP
atr = df.iloc[-1]['atr']
self.set_stop_loss_take_profit(
order['price'], signal, atr
)
else:
print(f"Current position: {current_position['side']} "
f"{current_position['contracts']} contracts")
# Wait before next iteration
print(f"{datetime.now()} - Waiting for next check...")
time.sleep(300) # Check every 5 minutes
except KeyboardInterrupt:
print("\nBot stopped by user")
break
except Exception as e:
print(f"Error in main loop: {e}")
time.sleep(60)
# ==================== Usage ====================
if __name__ == '__main__':
# WARNING: Never hardcode API keys in production!
# Use environment variables or config files
API_KEY = 'your_api_key_here'
API_SECRET = 'your_api_secret_here'
# Initialize bot
bot = CryptoTradingBot(
api_key=API_KEY,
api_secret=API_SECRET,
symbol='BTC/USDT',
timeframe='1h'
)
# Run bot
bot.run()
4. cTrader Automation (cAlgo) {#ctrader-automation}
🎯 cBot Template (C#)
using System;
using System.Linq;
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
using cAlgo.Indicators;
namespace cAlgo.Robots
{
[Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class SimpleMAcBot : Robot
{
// ==================== PARAMETERS ====================
[Parameter("Fast MA Period", DefaultValue = 10, MinValue = 1)]
public int FastPeriod { get; set; }
[Parameter("Slow MA Period", DefaultValue = 20, MinValue = 1)]
public int SlowPeriod { get; set; }
[Parameter("Risk Percent", DefaultValue = 2.0, MinValue = 0.1, MaxValue = 10)]
public double RiskPercent { get; set; }
[Parameter("Stop Loss (ATR)", DefaultValue = 2.0, MinValue = 0.5)]
public double StopLossATR { get; set; }
[Parameter("Take Profit (ATR)", DefaultValue = 3.0, MinValue = 0.5)]
public double TakeProfitATR { get; set; }
[Parameter("Instance Name", DefaultValue = "MA_Bot")]
public string InstanceName { get; set; }
// ==================== INDICATORS ====================
private MovingAverage fastMA;
private MovingAverage slowMA;
private AverageTrueRange atr;
// ==================== VARIABLES ====================
private const string Label = "MA_cBot";
// ==================== INITIALIZATION ====================
protected override void OnStart()
{
// Initialize indicators
fastMA = Indicators.MovingAverage(Bars.ClosePrices, FastPeriod, MovingAverageType.Simple);
slowMA = Indicators.MovingAverage(Bars.ClosePrices, SlowPeriod, MovingAverageType.Simple);
atr = Indicators.AverageTrueRange(14, MovingAverageType.Simple);
Print("cBot started successfully");
Print($"Risk per trade: {RiskPercent}%");
}
// ==================== ON BAR ====================
protected override void OnBar()
{
// Check if we already have a position
if (Positions.Find(Label, SymbolName) != null)
return;
// Get indicator values
double fastMANow = fastMA.Result.LastValue;
double slowMANow = slowMA.Result.LastValue;
double fastMAPrev = fastMA.Result.Last(1);
double slowMAPrev = slowMA.Result.Last(1);
// Long signal: Fast MA crosses above Slow MA
if (fastMAPrev <= slowMAPrev && fastMANow > slowMANow)
{
OpenLongPosition();
}
// Short signal: Fast MA crosses below Slow MA
else if (fastMAPrev >= slowMAPrev && fastMANow < slowMANow)
{
OpenShortPosition();
}
}
// ==================== OPEN LONG POSITION ====================
private void OpenLongPosition()
{
double atrValue = atr.Result.LastValue;
double entryPrice = Symbol.Ask;
double stopLoss = entryPrice - (StopLossATR * atrValue);
double takeProfit = entryPrice + (TakeProfitATR * atrValue);
// Calculate position size based on risk
double stopLossInPips = (entryPrice - stopLoss) / Symbol.PipSize;
long volume = CalculateVolume(stopLossInPips);
var result = ExecuteMarketOrder(TradeType.Buy, SymbolName, volume, Label, stopLossInPips, TakeProfitATR * atrValue / Symbol.PipSize);
if (result.IsSuccessful)
{
Print($"Long position opened at {entryPrice}");
Print($"SL: {stopLoss} | TP: {takeProfit}");
Print($"Volume: {volume} units");
}
else
{
Print($"Error opening long position: {result.Error}");
}
}
// ==================== OPEN SHORT POSITION ====================
private void OpenShortPosition()
{
double atrValue = atr.Result.LastValue;
double entryPrice = Symbol.Bid;
double stopLoss = entryPrice + (StopLossATR * atrValue);
double takeProfit = entryPrice - (TakeProfitATR * atrValue);
// Calculate position size based on risk
double stopLossInPips = (stopLoss - entryPrice) / Symbol.PipSize;
long volume = CalculateVolume(stopLossInPips);
var result = ExecuteMarketOrder(TradeType.Sell, SymbolName, volume, Label, stopLossInPips, TakeProfitATR * atrValue / Symbol.PipSize);
if (result.IsSuccessful)
{
Print($"Short position opened at {entryPrice}");
Print($"SL: {stopLoss} | TP: {takeProfit}");
Print($"Volume: {volume} units");
}
else
{
Print($"Error opening short position: {result.Error}");
}
}
// ==================== CALCULATE VOLUME ====================
private long CalculateVolume(double stopLossInPips)
{
double riskAmount = Account.Balance * (RiskPercent / 100);
double volumeInUnits = riskAmount / (stopLossInPips * Symbol.PipValue);
// Normalize volume
volumeInUnits = Symbol.NormalizeVolumeInUnits(volumeInUnits, RoundingMode.Down);
// Ensure volume is within limits
if (volumeInUnits < Symbol.VolumeInUnitsMin)
volumeInUnits = Symbol.VolumeInUnitsMin;
if (volumeInUnits > Symbol.VolumeInUnitsMax)
volumeInUnits = Symbol.VolumeInUnitsMax;
return (long)volumeInUnits;
}
// ==================== ON STOP ====================
protected override void OnStop()
{
Print("cBot stopped");
}
}
}
5. Backtesting Frameworks {#backtesting-frameworks}
🎯 Key Backtesting Principles
1. Data Quality
- Use tick data or high-quality OHLCV
- Account for splits, dividends (stocks)
- Handle missing data properly
- Avoid survivorship bias
2. Realistic Simulation
- Include commissions/fees
- Model slippage
- Respect liquidity constraints
- Account for latency
3. Validation
- Walk-forward analysis
- Out-of-sample testing
- Monte Carlo simulation
- Stress testing
4. Performance Metrics
✅ Sharpe Ratio (risk-adjusted return)
✅ Max Drawdown (worst peak-to-trough)
✅ Win Rate (% of winning trades)
✅ Profit Factor (gross profit / gross loss)
✅ Expectancy (average $ per trade)
✅ Recovery Factor (net profit / max DD)
✅ Calmar Ratio (annual return / max DD)
6. Strategy Optimization {#strategy-optimization}
🎯 Parameter Optimization Best Practices
1. Grid Search (Exhaustive)
# Test all combinations
fast_periods = range(5, 20, 1)
slow_periods = range(20, 50, 2)
for fast in fast_periods:
for slow in slow_periods:
if slow > fast:
result = backtest_strategy(fast, slow)
# Store results
2. Walk-Forward Optimization
Training Period: 2020-01 to 2021-12 → Optimize parameters
Testing Period: 2022-01 to 2022-12 → Test with optimal params
Rolling window:
- Train: Year 1-2
- Test: Year 3
- Train: Year 2-3
- Test: Year 4
3. Avoid Overfitting
- Use out-of-sample testing
- Limit number of parameters
- Penalize complexity (Occam's Razor)
- Validate on different time periods
- Test on multiple symbols
7. Order Management Systems {#order-management-systems}
🎯 Essential Order Management Features
1. Order Types
- Market Order (immediate execution)
- Limit Order (specific price)
- Stop Loss (exit on loss)
- Take Profit (exit on gain)
- Trailing Stop (dynamic SL)
- Stop Limit (stop → limit)
- OCO (One-Cancels-Other)
- Bracket Orders (entry + SL + TP)
2. Position Management
class PositionManager:
def __init__(self):
self.positions = {}
def add_position(self, symbol, side, quantity, entry_price):
"""Add new position"""
self.positions[symbol] = {
'side': side,
'quantity': quantity,
'entry_price': entry_price,
'current_price': entry_price,
'pnl': 0,
'stop_loss': None,
'take_profit': None
}
def update_price(self, symbol, current_price):
"""Update position PnL"""
if symbol in self.positions:
pos = self.positions[symbol]
if pos['side'] == 'long':
pos['pnl'] = (current_price - pos['entry_price']) * pos['quantity']
else: # short
pos['pnl'] = (pos['entry_price'] - current_price) * pos['quantity']
pos['current_price'] = current_price
def check_stops(self, symbol):
"""Check if SL/TP hit"""
if symbol not in self.positions:
return None
pos = self.positions[symbol]
# Check stop loss
if pos['stop_loss']:
if pos['side'] == 'long' and pos['current_price'] <= pos['stop_loss']:
return 'stop_loss'
elif pos['side'] == 'short' and pos['current_price'] >= pos['stop_loss']:
return 'stop_loss'
# Check take profit
if pos['take_profit']:
if pos['side'] == 'long' and pos['current_price'] >= pos['take_profit']:
return 'take_profit'
elif pos['side'] == 'short' and pos['current_price'] <= pos['take_profit']:
return 'take_profit'
return None
8. Risk Management Integration {#risk-management-integration}
🎯 Position Sizing Methods
1. Fixed Percentage
def fixed_percent_size(account_balance, risk_percent, stop_loss_distance):
"""
Risk 2% of account per trade
"""
risk_amount = account_balance * (risk_percent / 100)
position_size = risk_amount / stop_loss_distance
return position_size
2. Kelly Criterion
def kelly_criterion(win_rate, avg_win, avg_loss):
"""
Optimal position size based on edge
Kelly % = (Win Rate × Avg Win - Loss Rate × Avg Loss) / Avg Win
"""
loss_rate = 1 - win_rate
kelly_percent = (win_rate * avg_win - loss_rate * avg_loss) / avg_win
# Use fractional Kelly (e.g., 0.5 Kelly) to reduce volatility
return kelly_percent * 0.5
3. Volatility-Based (ATR)
def atr_position_size(account_balance, risk_percent, atr_value, atr_multiplier):
"""
Size based on ATR (volatility)
"""
risk_amount = account_balance * (risk_percent / 100)
stop_loss_distance = atr_value * atr_multiplier
position_size = risk_amount / stop_loss_distance
return position_size
9. VPS Deployment & Monitoring {#vps-deployment}
🎯 VPS Setup Checklist
1. Server Requirements
✅ Windows Server (for MetaTrader) or Linux (for Python/cTrader)
✅ Minimum 2GB RAM
✅ SSD storage
✅ Low latency to broker servers
✅ 99.9% uptime guarantee
✅ Automatic restart on failure
2. Security
✅ Firewall configuration
✅ Regular security updates
✅ Encrypted API keys
✅ VPN access only
✅ Two-factor authentication
✅ Regular backups
3. Monitoring
import logging
import smtplib
from email.mime.text import MIMEText
class BotMonitor:
def __init__(self, email_recipient):
self.email = email_recipient
self.logger = logging.getLogger('BotMonitor')
# Setup logging
logging.basicConfig(
filename='bot_log.txt',
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
def log_trade(self, trade_info):
"""Log trade execution"""
self.logger.info(f"Trade executed: {trade_info}")
def send_alert(self, subject, message):
"""Send email alert"""
try:
msg = MIMEText(message)
msg['Subject'] = subject
msg['From'] = 'bot@example.com'
msg['To'] = self.email
# Send email (configure SMTP server)
# ...
self.logger.info(f"Alert sent: {subject}")
except Exception as e:
self.logger.error(f"Failed to send alert: {e}")
def check_bot_health(self):
"""Check if bot is running properly"""
# Implement health checks:
# - Connection to broker
# - Recent trade activity
# - Account balance
# - Error rates
pass
10. Production Best Practices {#production-best-practices}
🎯 Pre-Launch Checklist
1. Testing
✅ Backtest on 3+ years of data
✅ Walk-forward optimization
✅ Paper trading for 1-3 months
✅ Test on demo account first
✅ Small live account test
✅ Stress test with extreme market conditions
2. Risk Controls
✅ Max loss per trade (2%)
✅ Max daily loss (6%)
✅ Max weekly loss (10%)
✅ Max drawdown limit (20%)
✅ Position size limits
✅ Correlation limits (multiple pairs)
✅ Emergency stop mechanism
3. Error Handling
import time
def safe_execute(func, max_retries=3, retry_delay=5):
"""
Execute function with retry logic
"""
for attempt in range(max_retries):
try:
return func()
except Exception as e:
print(f"Attempt {attempt + 1} failed: {e}")
if attempt < max_retries - 1:
time.sleep(retry_delay)
else:
raise
4. Logging & Monitoring
# Log everything:
- All trades (entry, exit, P/L)
- All errors and exceptions
- API calls and responses
- Account balance changes
- Parameter changes
- System health metrics
5. Documentation
✅ Strategy logic documented
✅ Parameter explanations
✅ Setup instructions
✅ Troubleshooting guide
✅ Emergency procedures
✅ Contact information
📊 Platform Comparison Matrix
| Feature | MetaTrader 4/5 | TradingView | Python | cTrader |
|---|---|---|---|---|
| Language | MQL4/MQL5 | Pine Script | Python | C# |
| Ease of Learning | Medium | Easy | Hard | Medium |
| Backtesting | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| Optimization | ⭐⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| Live Trading | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| Broker Support | Excellent | Good | Universal | Good |
| Community | Huge | Huge | Huge | Medium |
| Cost | Free | Free/Pro | Free | Free |
| Best For | Forex/CFD | Multi-market | Algo traders | ECN/Pro traders |
🎓 Learning Path Roadmap
Level 1: Foundations (Weeks 1-4)
✅ Learn platform basics (MT4/TradingView/Python)
✅ Understand basic indicators (MA, RSI, MACD)
✅ Code simple "Hello World" EA
✅ Run first backtest
✅ Understand OHLCV data structure
Level 2: Strategy Development (Weeks 5-12)
✅ Code MA crossover strategy
✅ Add risk management (SL/TP)
✅ Implement position sizing
✅ Backtest with realistic parameters
✅ Paper trade for 1 month
Level 3: Advanced Features (Weeks 13-24)
✅ Multi-timeframe analysis
✅ Advanced indicators (ATR, Bollinger)
✅ Trailing stops
✅ Portfolio management
✅ Walk-forward optimization
Level 4: Production Deployment (Weeks 25-52)
✅ VPS setup and deployment
✅ Monitoring and logging
✅ Error handling and recovery
✅ Live trading with small capital
✅ Performance analysis and iteration
⚠️ Critical Warnings
1. Risk of Ruin
- Never risk more than 2% per trade
- Drawdowns are inevitable
- Past performance ≠ future results
- Test extensively before going live
2. Technical Risks
- Internet connection failures
- VPS downtime
- Broker API changes
- Exchange outages
- Bug in code → unexpected behavior
3. Market Risks
- Black swan events
- Flash crashes
- Low liquidity periods
- Slippage > expected
- News events → high volatility
4. Psychological Risks
- Over-optimization (curve fitting)
- Revenge trading (manual intervention)
- Greed (increasing risk after wins)
- Fear (stopping bot after losses)
🎯 Key Takeaways
✅ DO:
- Start small, test thoroughly
- Use proper risk management
- Log everything
- Monitor continuously
- Keep strategies simple
- Diversify across strategies/symbols
- Have kill-switch mechanism
❌ DON'T:
- Risk more than you can afford to lose
- Over-optimize on past data
- Ignore transaction costs
- Use untested code in production
- Run unmonitored bots
- Believe in "holy grail" systems
- Leverage excessively
📚 Additional Resources
MetaTrader:
- MQL4 Documentation: https://docs.mql4.com/
- MQL5 Documentation: https://www.mql5.com/en/docs
TradingView:
- Pine Script Reference: https://www.tradingview.com/pine-script-reference/
Python:
- Backtrader Docs: https://www.backtrader.com/docu/
- CCXT Docs: https://docs.ccxt.com/
cTrader:
- cAlgo API: https://ctrader.com/api/
Remember: Automation is a tool, not a guarantee of profit. Success requires solid strategy, rigorous testing, disciplined risk management, and continuous monitoring.
Next Steps: Start with simple strategies, master one platform, test thoroughly, then gradually increase complexity. 🚀