Импульсная торговля — это популярная и динамичная инвестиционная стратегия, цель которой — извлечь выгоду из продолжения существующих рыночных тенденций. Эта стратегия направлена ​​на выявление и управление импульсом акций, товаров или других финансовых инструментов, которые демонстрируют сильные восходящие или нисходящие движения цен. Импульсные трейдеры считают, что эти тенденции сохранятся в краткосрочной перспективе, что позволит им получать прибыль, соответственно покупая или продавая активы.

Первым ключевым моментом импульсной стратегии является разработка сигналов, которые будут использоваться для принятия торговых решений. Эти сигналы создаются с использованием экспоненциально-взвешенного среднего (EWM). Для расчета конвергенции/расхождения скользящих средних (MACD) вычисляется EWM за последние 26 и 12 дней, после чего 26-дневный EWM вычитается из 12-дневного EWM, чтобы получить MACD (быстрая сигнальная линия). После расчета MACD сигнальная линия выводится для анализа путем расчета 9-дневного EWM линии MACD.

import yfinance as yf
import pandas as pd
from datetime import date, timedelta

def multipler(n): return (2/(n+1))

def calculate_signals(data):
    # Calculate the MACD or Fast Line
    upperMulti, lowerMulti = multipler(26), multipler(12)
    
    upperEWM = list(data.iloc[:26]['Adj Close'])
    LowerEWM = list(data.iloc[:12]['Adj Close'])

    uEWM = sum(upperEWM) / 26
    lEWM = sum(LowerEWM) / 12
    
    for i in range(12, len(data)):
        adjClose = data.iloc[i]['Adj Close']
        lEWM = (adjClose * lowerMulti) + (lEWM * (1 - lowerMulti))
        LowerEWM.append(lEWM)
        if i >= 26:
            uEWM = (adjClose * upperMulti) + (uEWM * (1 - upperMulti))
            upperEWM.append(uEWM)
    
    data['MACD'] = [round(LowerEWM[i] - upperEWM[i], 6) for i in range(len(upperEWM))]
    
    # Calculate the signal line
    smallMulti = multipler(9)
    
    smallEWM = list(data.iloc[:9]['MACD'])
    
    sEWM = sum(smallEWM) / 9
    
    for i in range(9, len(data)):
        newLEWM = (data.iloc[i]['MACD'] * smallMulti) + (sEWM * (1 - smallMulti))
        smallEWM.append(newLEWM)
        sEWM = newLEWM
        
    data['Signal'] = smallEWM
    
    return data

Второй ключевой момент — разработка системы, определяющей, покупать или продавать по каждой текущей позиции. Есть три основных правила для этой реализации:

  1. Если сигнальная линия ниже линии MACD, трейдер будет покупать/длинную позицию по текущей позиции.
  2. Если сигнальная линия выше линии MACD, трейдер будет продавать/коротить текущую позицию.
  3. Трейдер может купить позицию только в том случае, если последней совершенной сделкой была продажа.
def position_analysis(data, transaction, balance):
    
    if transaction['Buy'].iloc[-1] == False:
        # If singal is less than MACD then we buy
        if data['MACD'].iloc[-1] > data['Signal'].iloc[-1]:
            Quantity = balance / data['Adj Close'].iloc[-1]

            return({'Price': data['Adj Close'].iloc[-1], 'Quantity': Quantity, 'Buy': True, 
                    'Sell': False}, 0)
            
    else:
        # If price is getting too close to buying point then sell or Singnal more than MACD
        if data['Adj Close'].iloc[-1] < transaction['Price'].iloc[-1] or data['MACD'].iloc[-1] < data['Signal'].iloc[-1]:
            balance += (transaction['Quantity'].iloc[-1] * data['Adj Close'].iloc[-1])
            
            return({'Price': data['Adj Close'].iloc[-1], 'Quantity': transaction['Quantity'].iloc[-1], 
                    'Buy': False, 'Sell': True}, balance)
    
    return(None, balance)

Последний ключевой момент — провести полное тестирование системы на исторических данных и оценить окончательный баланс после 250 дней торговли. Например, при тестировании акций «CANE» с использованием данных Yahoo Finance алгоритм дал прибыль примерно в 21,24%. Однако важно отметить, что алгоритм не всегда обеспечивает постоянную прибыль по всем акциям. Например, «AAPL» принес 5% прибыли, а «MSFT» показал прибыль -6%.

'''Function to calaculate the total balance after exectution'''
def work_equity(balance, transaction):
    if transaction['Buy'].iloc[-1] == True:
        return print(transaction['Quantity'].iloc[-1] * transaction['Price'].iloc[-1])
    else:
        return print(balance)

'''Main Functions for Running all Processes'''
def controller(end_date, start_date, ticker):
    # Get the data and organise it appropriatly 
    data = calculate_signals(yf.download(ticker, start_date, end_date))
    # Create the tranaction list for trading, show all transactions made
    tempData = [[1, 1, False, False]]
    transaction = pd.DataFrame(tempData, columns=['Price', 'Quantity', 'Buy', 'Sell'])
    balance = 100
    
    # Loops through the data and performs for each of them
    for x in range(26, len(data)):
        trans, balance = position_analysis(data.iloc[:x], transaction, balance)
        # If no return then we haven't done anything to the data, if there is we edit the transactions
        if trans is not None:
            transaction = pd.concat([transaction, pd.DataFrame(trans, index=[0])]).reset_index(drop = True)
    
    print(transaction)
    work_equity(balance, transaction)
    
    return

ticker = 'CANE'
end_date = date.today()
start_date = end_date - timedelta(days = 250)
controller(end_date, start_date, ticker)

В целом, мой алгоритм демонстрирует некоторую эффективность и может использовать алгоритмические характеристики для достижения благоприятных результатов торговли. Для дальнейшего улучшения программы я планирую включить дополнительные системы, такие как импульс сектора и стратегии хеджирования.