背景 Background
最近想学习一下量化金融,总算在盈透投资者教育(IBKRCampus)板块找到一篇比较好的算法交易入门教程。我在记录实践过程后,翻译成中文写成此csdn博客,分享给大家。
如果你的英语好可以直接看原文。原文在数据准备阶段,采用了 pandas_datareader.data 读取网络数据,实际中出现了很多问题,我换成了 yfinance。可以参考文末完整代码。
参考资料:https://www.interactivebrokers.com/campus/ibkr-quant-news/basic-trading-algorithms-in-python/
算法交易简介 Introduction
算法交易的兴起改变了金融市场,让交易者能够在数据驱动下做出精确的决策。具备 Pandas 和 NumPy 等强大第三方库的 Python 语言是开发交易算法的首选。本文将指导您利用这些库在 Python 中创建基本的交易算法。
算法交易,指的是使用远超过人类能力的计算机程序,去提升交易速度和频率,这些算法通过分析市场数据,观察交易时机,基于预先给定的规则去执行交易命令。
算法交易有一些核心优势,包括
-
速度:指令可以在低于百万分之一秒的时间内运行
-
准确度:减少人类的操作误差
-
连续性:持续操作,不会像人类一样感到疲倦
为什么使用 Python 进行交易 Why Use Python
Python的简洁语法和灵活性(支持大量不同种类的第三方库),使其成为交易算法的理想语言。这篇文章主要聚焦于两个主要的第三方库:Pandas和NumPy。
-
Pandas:对于数据管理和分析,提供了一系列数据结构和函数,可以毫不费力与这些结构化数据协同工作
-
NumPy:对于数学计算,处理巨大的、多维的数组和矩阵,有一系列配套的数学函数。
其他有用的Python库包括:
- scikit-learning:用于在算法交易中加入机器学习内容
- matplotlib:用于过程和结构的数据可视化
准备开发环境 Environment
创建 Conda 环境
安装 Pandas 和 NumPy 库
数据获取和预处理 Data preparation
import yfinance as yf
import datetime
import numpy as np
# data preparation
# Define the start and end date
start = datetime.datetime(2020, 1, 1)
end = datetime.datetime(2022, 1, 1)
# Fetch data for a particular stock
stock_data = yf.download('AAPL', start='2022-01-01', end='2022-12-31')
print(stock_data.head())
计算技术指标 Technical Indicators
移动均线 Moving Average(MA)
# technical indicator
# Simple Moving Average (SMA)
stock_data['SMA_20'] = stock_data['Adj Close'].rolling(window=20).mean()
# Exponential Moving Average (EMA)
stock_data['EMA_20'] = stock_data['Adj Close'].ewm(span=20, adjust=False).mean()
相对力量指数 Relative Strength Index(RSI)
# RSI
def calculate_rsi(data, window):
delta = data['Adj Close'].diff(1)
gain = (delta.where(delta > 0, 0)).rolling(window=window).mean()
loss = (-delta.where(delta < 0, 0)).rolling(window=window).mean()
rs = gain / loss
rsi = 100 - (100 / (1 + rs))
return rsi
stock_data['RSI_14'] = calculate_rsi(stock_data, 14)
一个基础的交易算法 A Basic Trading Algorithm
定义策略 Define the Strategy
# Define a strategy
# Calculate longer-term SMA
stock_data['SMA_50'] = stock_data['Adj Close'].rolling(window=50).mean()
# Create buy/sell signals
stock_data['Signal'] = 0
stock_data.loc[stock_data.index[20]:, 'Signal'] = np.where(stock_data.loc[stock_data.index[20]:, 'SMA_20'] > stock_data.loc[stock_data.index[20]:, 'SMA_50'], 1, 0)
stock_data['Position'] = stock_data['Signal'].diff()
回测策略 Backtesting the Strategy
# Backtest
initial_capital = 100000.0
stock_data['Holdings'] = stock_data['Adj Close'] * stock_data['Position'].cumsum()
stock_data['Cash'] = initial_capital - (stock_data['Adj Close'] * stock_data['Position']).cumsum()
stock_data['Total'] = stock_data['Cash'] + stock_data['Holdings']
分析结果 Analyzing the Results
# Analizing results
cumulative_returns = (stock_data['Total'].iloc[-1] - initial_capital) / initial_capital
average_daily_returns = stock_data['Returns'].mean()
volatility = stock_data['Returns'].std()
print("Cumulative Returns: {:.2f}%".format(cumulative_returns * 100))
print("Average Daily Returns: {:.4f}".format(average_daily_returns))
print("Volatility: {:.4f}".format(volatility))
结论 Conclusion
利用Python的Pandas和NumPy库,开发基础交易算法,是一个有利的手段,去驱使数据为交易决定增加信息。这篇文章提供了一个基础的指导去准备数据、计算技术指标、完成一个简单的交易策略和评估其表现。
当你继续探索和试图打磨你的算法的时候,记住金融市场是复杂和持续变化的。
不断的学习和适应市场环境,是在算法交易中取得成功的关键。
完整代码 Code
import yfinance as yf
import datetime
import numpy as np
# data preparation
# Define the start and end date
start = datetime.datetime(2020, 1, 1)
end = datetime.datetime(2022, 1, 1)
# Fetch data for a particular stock
stock_data = yf.download('AAPL', start='2022-01-01', end='2022-12-31')
print(stock_data.head())
# technical indicator
# Simple Moving Average (SMA)
stock_data['SMA_20'] = stock_data['Adj Close'].rolling(window=20).mean()
# Exponential Moving Average (EMA)
stock_data['EMA_20'] = stock_data['Adj Close'].ewm(span=20, adjust=False).mean()
# RSI
def calculate_rsi(data, window):
delta = data['Adj Close'].diff(1)
gain = (delta.where(delta > 0, 0)).rolling(window=window).mean()
loss = (-delta.where(delta < 0, 0)).rolling(window=window).mean()
rs = gain / loss
rsi = 100 - (100 / (1 + rs))
return rsi
stock_data['RSI_14'] = calculate_rsi(stock_data, 14)
# Define a strategy
# Calculate longer-term SMA
stock_data['SMA_50'] = stock_data['Adj Close'].rolling(window=50).mean()
# Create buy/sell signals
stock_data['Signal'] = 0
stock_data.loc[stock_data.index[20]:, 'Signal'] = np.where(stock_data.loc[stock_data.index[20]:, 'SMA_20'] > stock_data.loc[stock_data.index[20]:, 'SMA_50'], 1, 0)
stock_data['Position'] = stock_data['Signal'].diff()
# Backtest
initial_capital = 100000.0
stock_data['Holdings'] = stock_data['Adj Close'] * stock_data['Position'].cumsum()
stock_data['Cash'] = initial_capital - (stock_data['Adj Close'] * stock_data['Position']).cumsum()
stock_data['Total'] = stock_data['Cash'] + stock_data['Holdings']
# Calculate returns
stock_data['Returns'] = stock_data['Total'].pct_change()
# Print final portfolio value
print("Final Portfolio Value: ${}".format(stock_data['Total'].iloc[-1]))
# Analizing results
cumulative_returns = (stock_data['Total'].iloc[-1] - initial_capital) / initial_capital
average_daily_returns = stock_data['Returns'].mean()
volatility = stock_data['Returns'].std()
print("Cumulative Returns: {:.2f}%".format(cumulative_returns * 100))
print("Average Daily Returns: {:.4f}".format(average_daily_returns))
print("Volatility: {:.4f}".format(volatility))