Читать книгу Алгоритмический трейдинг: Создание, тестирование и запуск роботов на рынке Форекс (Алексей Дмитриевич Боровков) онлайн бесплатно на Bookz (2-ая страница книги)
Алгоритмический трейдинг: Создание, тестирование и запуск роботов на рынке Форекс
Алгоритмический трейдинг: Создание, тестирование и запуск роботов на рынке Форекс
Оценить:

3

Полная версия:

Алгоритмический трейдинг: Создание, тестирование и запуск роботов на рынке Форекс

self.current_trade['size']

)

self.current_trade['pnl_percent'] = (

(order.executed.price / self.current_trade['entry_price'] – 1) * 100

)

self.trades.append(self.current_trade.copy())

self.current_trade = {}


elif order.status in [order.Canceled, order.Margin, order.Rejected]:

self.log(f'Ордер отменен/отклонен: {order.getstatusname()}')


self.order = None


def notify_trade(self, trade):

"""Обработка изменения статуса сделки"""

if not trade.isclosed:

return


self.log(f'СДЕЛКА ЗАКРЫТА, Прибыль: {trade.pnl:.2f}, Чистая прибыль: {trade.pnlcomm:.2f}')


def next(self):

"""Основная логика на каждом новом баре"""

# Пропускаем если ордер уже открыт

if self.order:

return


# Проверяем, есть ли открытая позиция

if not self.position:

# УСЛОВИЕ ДЛЯ ПОКУПКИ:

# 1. Быстрая MA пересекает медленную снизу вверх

# 2. ADX > порогового значения (сила тренда)

crossover_up = (self.fast_ma[-1] < self.slow_ma[-1] and

self.fast_ma[0] > self.slow_ma[0])


strong_trend = self.adx[0] > self.params.adx_threshold


if crossover_up and strong_trend:

# Рассчитываем размер позиции на основе риска

capital = self.broker.getvalue()

risk_amount = capital * self.params.risk_per_trade


if self.params.use_atr_filter:

stop_distance = self.atr[0] * self.params.atr_multiplier

else:

stop_distance = self.data.close[0] * self.params.stop_loss


if stop_distance > 0:

size = risk_amount / stop_distance

size = min(size, capital * 0.1 / self.data.close[0]) # Не более 10% капитала


self.log(f'СИГНАЛ НА ПОКУПКУ: цена={self.data.close[0]:.2f}, '

f'ADX={self.adx[0]:.2f}, размер={size:.2f}')

self.order = self.buy(size=size)


else:

# УСЛОВИЕ ДЛЯ ЗАКРЫТИЯ ПОЗИЦИИ:

# Быстрая MA пересекает медленную сверху вниз

crossover_down = (self.fast_ma[-1] > self.slow_ma[-1] and

self.fast_ma[0] < self.slow_ma[0])


if crossover_down:

self.log(f'СИГНАЛ НА ЗАКРЫТИЕ: цена={self.data.close[0]:.2f}')

self.order = self.close()


# =====================================================================

# 2. КЛАСС ДЛЯ ОПТИМИЗАЦИИ ПАРАМЕТРОВ

# =====================================================================

class TrendFollowerOptimizer(bt.Strategy):

"""Версия стратегии для оптимизации параметров"""


params = (

('fast_ma', 50),

('slow_ma', 200),

('adx_threshold', 25),

('risk_per_trade', 0.01),

)


def __init__(self):

self.fast_ma = bt.indicators.SMA(self.data.close, period=self.p.fast_ma)

self.slow_ma = bt.indicators.SMA(self.data.close, period=self.p.slow_ma)

self.adx = bt.indicators.ADX(self.data, period=14)

self.order = None


def next(self):

if self.order:

return


if not self.position:

if (self.fast_ma[-1] < self.slow_ma[-1] and

self.fast_ma[0] > self.slow_ma[0] and

self.adx[0] > self.p.adx_threshold):


size = self.broker.getvalue() * self.p.risk_per_trade / self.data.close[0]

self.order = self.buy(size=size)

else:

if self.fast_ma[-1] > self.slow_ma[-1] and self.fast_ma[0] < self.slow_ma[0]:

self.order = self.close()


# =====================================================================

# 3. ФУНКЦИИ ДЛЯ ТЕСТИРОВАНИЯ И АНАЛИЗА

# =====================================================================

def download_data(symbol='EURUSD=X', start_date='2020-01-01', end_date='2023-12-31'):

"""Загрузка данных с Yahoo Finance"""

print(f"Загрузка данных для {symbol}…")

data = yf.download(symbol, start=start_date, end=end_date, progress=False)


# Преобразуем индексы для backtrader

data.index = pd.to_datetime(data.index)

data = data[['Open', 'High', 'Low', 'Close', 'Volume']]


return data


def run_backtest(data, initial_cash=10000, commission=0.001, **strategy_params):

"""Запуск бэктеста"""

cerebro = bt.Cerebro()


# Добавляем данные

data_feed = bt.feeds.PandasData(dataname=data)

cerebro.adddata(data_feed)


# Добавляем стратегию

cerebro.addstrategy(TrendFollowerStrategy, **strategy_params)


# Настройки брокера

cerebro.broker.setcash(initial_cash)

cerebro.broker.setcommission(commission=commission)


# Добавляем анализаторы

cerebro.addanalyzer(btanalyzers.Returns, _name='returns')

cerebro.addanalyzer(btanalyzers.SharpeRatio, _name='sharpe', riskfreerate=0.0)

cerebro.addanalyzer(btanalyzers.DrawDown, _name='drawdown')

cerebro.addanalyzer(btanalyzers.TradeAnalyzer, _name='trades')

cerebro.addanalyzer(btanalyzers.SQN, _name='sqn')


print(f'Начальный капитал: {initial_cash:.2f}')

print(f'Комиссия: {commission*100:.2f}%')


# Запуск

results = cerebro.run()

strat = results[0]


# Вывод результатов

print('\n' + '='*50)

print('РЕЗУЛЬТАТЫ БЭКТЕСТА')

print('='*50)


final_value = cerebro.broker.getvalue()

total_return = (final_value / initial_cash – 1) * 100


print(f'Конечный капитал: {final_value:.2f}')

print(f'Общая доходность: {total_return:.2f}%')


# Анализ результатов

if hasattr(strat, 'analyzers'):

returns = strat.analyzers.returns.get_analysis()

sharpe = strat.analyzers.sharpe.get_analysis()

drawdown = strat.analyzers.drawdown.get_analysis()

trades = strat.analyzers.trades.get_analysis()

sqn = strat.analyzers.sqn.get_analysis()


print(f'\nАНАЛИТИКА:')

print(f'Sharpe Ratio: {sharpe.get("sharperatio", 0):.3f}')

print(f'Максимальная просадка: {drawdown.max.drawdown:.2f}%')

print(f'Продолжительность просадки: {drawdown.max.len} дней')


if trades.total.total:

print(f'\nСТАТИСТИКА СДЕЛОК:')

print(f'Всего сделок: {trades.total.total}')

print(f'Прибыльных: {trades.won.total} ({trades.won.total/trades.total.total*100:.1f}%)')

print(f'Убыточных: {trades.lost.total} ({trades.lost.total/trades.total.total*100:.1f}%)')

print(f'Profit Factor: {trades.won.pnl.total/abs(trades.lost.pnl.total):.2f}')

print(f'Средняя прибыль: {trades.won.pnl.average:.2f}')

print(f'Средний убыток: {trades.lost.pnl.average:.2f}')

print(f'SQN: {sqn.sqn:.2f}')


# Возвращаем детали сделок для дальнейшего анализа

trades_details = getattr(strat, 'trades', [])


return cerebro, strat, trades_details


def optimize_parameters(data, parameter_ranges):

"""Оптимизация параметров стратегии"""

cerebro = bt.Cerebro(optreturn=False)


# Добавляем данные

data_feed = bt.feeds.PandasData(dataname=data)

cerebro.adddata(data_feed)


# Добавляем стратегию с параметрами для оптимизации

cerebro.optstrategy(

TrendFollowerOptimizer,

fast_ma=parameter_ranges.get('fast_ma', range(10, 101, 10)),

slow_ma=parameter_ranges.get('slow_ma', range(50, 301, 50)),

adx_threshold=parameter_ranges.get('adx_threshold', range(20, 41, 5)),

risk_per_trade=parameter_ranges.get('risk_per_trade', [0.005, 0.01, 0.02])

)


# Настройки

cerebro.broker.setcash(10000)

cerebro.broker.setcommission(commission=0.001)


# Оптимизация

print("Запуск оптимизации параметров…")

opt_results = cerebro.run(maxcpus=1)


# Анализ результатов оптимизации

results = []

for run in opt_results:

for strat in run:

# Собираем статистику для каждого набора параметров

value = cerebro.broker.getvalue()

returns = (value / 10000 – 1) * 100


results.append({

'fast_ma': strat.params.fast_ma,

'slow_ma': strat.params.slow_ma,

'adx_threshold': strat.params.adx_threshold,

'risk_per_trade': strat.params.risk_per_trade,

'final_value': value,

'returns': returns

})


# Создаем DataFrame с результатами

results_df = pd.DataFrame(results)

results_df = results_df.sort_values('final_value', ascending=False)


return results_df


def plot_results(cerebro, save_path='trend_follower_results.png'):

"""Визуализация результатов"""

# График 1: Кривая баланса

fig = cerebro.plot(style='candlestick', iplot=False)[0][0]

fig.set_size_inches(14, 8)

fig.suptitle('Trend Follower Strategy – Equity Curve', fontsize=16)


# Сохраняем график

plt.tight_layout()

plt.savefig(save_path, dpi=100, bbox_inches='tight')

plt.show()


return fig


def generate_report(strategy_params, trades_details, filename='trend_follower_report.txt'):

"""Генерация детального отчета"""

with open(filename, 'w', encoding='utf-8') as f:

f.write("="*60 + "\n")

f.write("ОТЧЕТ ПО СТРАТЕГИИ TREND FOLLOWER\n")

f.write("="*60 + "\n\n")


f.write("ПАРАМЕТРЫ СТРАТЕГИИ:\n")

f.write("-"*40 + "\n")

for key, value in strategy_params.items():

f.write(f"{key}: {value}\n")


f.write("\n" + "="*60 + "\n\n")


if trades_details:

f.write("ДЕТАЛИ СДЕЛОК:\n")

f.write("-"*40 + "\n")


total_pnl = 0

winning_trades = 0


for i, trade in enumerate(trades_details, 1):

pnl = trade.get('pnl', 0)

pnl_percent = trade.get('pnl_percent', 0)


f.write(f"\nСделка #{i}:\n")

f.write(f" Дата входа: {trade.get('entry_date')}\n")

f.write(f" Цена входа: {trade.get('entry_price', 0):.4f}\n")

f.write(f" Дата выхода: {trade.get('exit_date')}\n")

f.write(f" Цена выхода: {trade.get('exit_price', 0):.4f}\n")

f.write(f" P&L: {pnl:.2f} ({pnl_percent:.2f}%)\n")


total_pnl += pnl

if pnl > 0:

winning_trades += 1


f.write("\n" + "="*60 + "\n")

f.write(f"ИТОГИ:\n")

f.write(f"Всего сделок: {len(trades_details)}\n")

f.write(f"Прибыльных сделок: {winning_trades} ({winning_trades/len(trades_details)*100:.1f}%)\n")

f.write(f"Общий P&L: {total_pnl:.2f}\n")


print(f"Отчет сохранен в файл: {filename}")


# =====================================================================

# 4. ОСНОВНОЙ СКРИПТ ДЛЯ ЗАПУСКА

# =====================================================================

def main():

"""Основная функция для запуска бэктеста"""

print("="*60)

print("TREND FOLLOWER STRATEGY BACKTEST")

print("="*60)


# 1. Загружаем данные

symbol = 'EURUSD=X' # EUR/USD

data = download_data(

symbol=symbol,

start_date='2020-01-01',

end_date='2023-12-31'

Конец ознакомительного фрагмента.

Текст предоставлен ООО «Литрес».

Прочитайте эту книгу целиком, купив полную легальную версию на Литрес.

Безопасно оплатить книгу можно банковской картой Visa, MasterCard, Maestro, со счета мобильного телефона, с платежного терминала, в салоне МТС или Связной, через PayPal, WebMoney, Яндекс.Деньги, QIWI Кошелек, бонусными картами или другим удобным Вам способом.

Вы ознакомились с фрагментом книги.

Для бесплатного чтения открыта только часть текста.

Приобретайте полный текст книги у нашего партнера:


Полная версия книги

Всего 10 форматов

bannerbanner