在上一节中,我们学习了如何获取股票的均线数据。在本节中,我们将尝试搭建一个简单的单均线交易系统。该系统的规则是:当股价突破均线时买入,当股价跌破均线时卖出。我们仍然只使用收盘价,因为盘中价格的噪音太多。
获取股票价格数据
首先,我们需要用到之前讲的,获取股票的价格数据。
import yfinance as yf
def get_prices(stock_symbol):
data = yf.download(stock_symbol)
return data
确定交易规则
接下来,我们需要确定交易规则:
- 如果没有持仓,当股价向上突破均线时满仓买入。
- 如果持仓状态下,当股价跌破均线时全部卖出。
这里我们要用到上一节讲的移动平均线的计算方法,以及一个python的内置函数zip用来遍历每个交易日的价格数据。但是要注意sma中最开始的数据是没有的,比如20天均线要到第20天才会有均值数据。这里需要用numpy来确认一下sma是否有数据,代码如下:
import numpy as np
def main():
prices = get_prices("^NDX")
sma_20 = prices['Adj Close'].rolling(window=20).mean() # 20日均线
# 初始化持仓状态
in_position = False
entry_price = 0
# 遍历每个交易日的价格数据
for date, price, sma_value in zip(prices.index, prices['Adj Close'], sma_20):
if not np.isnan(sma_value): # 忽略均线计算前的NaN值
if price > sma_value and not in_position: # 突破均线且当前不在持仓中
print(f"在 {date} 以价格 {price} 买入")
in_position = True
entry_price = price
elif price < sma_value and in_position: # 跌破均线且当前持仓中
print(f"在 {date} 以价格 {price} 卖出")
in_position = False
profit = price - entry_price
print(f"交易盈利: {profit}")
if __name__ == '__main__':
main()
考虑资本和持仓量
不过这里有个问题,现在的profit是买入和卖出的差价,并不是我们实际的盈利情况。因此,我们引入了初始资本、现金和股票数量等变量,并在交易过程中实时更新这些变量。初始现金等于初始资本,初始股票数量是0。
def main():
prices = get_prices("^NDX")
sma_20 = prices['Adj Close'].rolling(window=20).mean() # 20日均线
# 初始化持仓状态
in_position = False
entry_price = 0
initial_capital = 1000
cash = initial_capital
stock_quantity = 0
# 遍历每个交易日的价格数据
for date, price, sma_value in zip(prices.index, prices['Adj Close'], sma_20):
if not np.isnan(sma_value): # 忽略均线计算前的NaN值
if price > sma_value and not in_position: # 突破均线且当前不在持仓中
print(f"在 {date} 以价格 {price} 买入")
in_position = True
entry_price = price
stock_quantity = cash / price
cash = 0
print(f"买入股票数量{stock_quantity},现金清零")
elif price < sma_value and in_position: # 跌破均线且当前持仓中
print(f"在 {date} 以价格 {price} 卖出")
in_position = False
profit = price - entry_price
print(f"交易盈利: {profit}")
cash = stock_quantity * price
print(f"卖出股票数量{stock_quantity},获得现金{cash}")
print(f"总资产为{cash + stock_quantity * price}")
if __name__ == '__main__':
main()
将策略整理为函数
最后,我们将单均线交易策略整理为一个函数,以便于后续测试和调用。
import yfinance as yf
import numpy as np
def get_prices(stock_symbol):
data = yf.download(stock_symbol)
return data
def get_simple_moving_average(prices,
window_size):
sma_20 = prices['Adj Close'].rolling(window=window_size).mean() # 20日均线
return sma_20
def single_moving_average_strategy(initial_capital, prices, sma_window_size):
in_position = False
entry_price = 0
cash = initial_capital
stock_quantity = 0
sma = get_simple_moving_average(prices, sma_window_size)
# 遍历每个交易日的价格数据
for date, price, sma_value in zip(prices.index, prices['Adj Close'], sma):
if not np.isnan(sma_value): # 忽略均线计算前的NaN值
if price > sma_value and not in_position: # 突破均线且当前不在持仓中
print(f"在 {date} 以价格 {price} 买入")
in_position = True
entry_price = price
stock_quantity = cash / price
cash = 0
print(f"买入股票数量{stock_quantity},现金清零")
elif price < sma_value and in_position: # 跌破均线且当前持仓中
print(f"在 {date} 以价格 {price} 卖出")
in_position = False
profit = price - entry_price
print(f"交易盈利: {profit}")
cash = stock_quantity * price
print(f"卖出股票数量{stock_quantity},获得现金{cash}")
print(f"总资产为{cash + stock_quantity * price}")
def main():
prices = get_prices("^NDX")
single_moving_average_strategy(1000, prices, 50)
if __name__ == '__main__':
main()
现在,你可以在修改股票代码和均线长度来回测收益啦。