前情回顾
在前面我们实现了2中方法进行数字货币交易,同时还能获取到实时行情。数字货币交易接口实现(含源代码)。
在此基础上,我们今天实现一个指标策略自动化交易的功能(以MACD指标为例),并进行2次优化,增加仓位管理以及风险控制的功能,实现一个完成的交易策略。
MACD 策略逻辑
- 获取 5 分钟的 K 线数据
- 计算 MACD 指标
- 买入条件:MACD 越过零线
- 卖出条件:MACD 低于零线
代码实现
import ccxt
import pandas as pd
import ta
import time
# 初始化 Binance 交易所实例
exchange = ccxt.binance({
'apiKey': 'YOUR_API_KEY', # 替换为你的 API Key
'secret': 'YOUR_SECRET_KEY', # 替换为你的 Secret Key
})
# 获取 5 分钟的 K 线数据
def fetch_ohlcv(symbol, timeframe='5m', limit=100):
ohlcv = exchange.fetch_ohlcv(symbol, timeframe, limit=limit)
df = pd.DataFrame(ohlcv, columns=['timestamp', 'open', 'high', 'low', 'close', 'volume'])
df['timestamp'] = pd.to_datetime(df['timestamp'], unit='ms')
df.set_index('timestamp', inplace=True)
return df
# 计算 MACD 指标
def calculate_macd(df):
macd = ta.trend.MACD(df['close'])
df['macd'] = macd.macd()
df['macd_signal'] = macd.macd_signal()
df['macd_diff'] = macd.macd_diff()
# 检查交易信号
def check_trade_signals(df):
last_row = df.iloc[-1]
previous_row = df.iloc[-2]
# 买入条件:MACD 越过零线
if previous_row['macd'] < 0 and last_row['macd'] > 0:
return 'buy'
# 卖出条件:MACD 低于零线
if previous_row['macd'] > 0 and last_row['macd'] < 0:
return 'sell'
return 'hold'
# 执行交易
def execute_trade(signal, symbol='BTC/USDT', amount=0.001):
if signal == 'buy':
order = exchange.create_market_buy_order(symbol, amount)
print('Buy order executed:', order)
elif signal == 'sell':
order = exchange.create_market_sell_order(symbol, amount)
print('Sell order executed:', order)
# 主循环
def main():
symbol = 'BTC/USDT'
while True:
df = fetch_ohlcv(symbol)
calculate_macd(df)
calculate_ema(df)
calculate_kdj(df)
signal = check_trade_signals(df)
execute_trade(signal)
time.sleep(300) # 每5分钟运行一次
if __name__ == "__main__":
main()
代码说明
1、初始化 Binance 交易所实例:使用你的 API Key 和 Secret Key 初始化 ccxt 库中的 Binance 实例。
2、获取 5 分钟的 K 线数据:定义 fetch_ohlcv 函数,从 Binance 获取指定交易对的 5 分钟 K 线数据,并将其转换为 Pandas DataFrame。
3、计算 MACD 指标:定义相应的函数计算这些技术指标,并将其添加到 DataFrame 中。
4、检查交易信号:定义 check_trade_signals 函数,根据 MACD 越过零线和低于零线的条件检查交易信号。
5、执行交易:定义 execute_trade 函数,根据交易信号执行买入或卖出操作。
6、主循环:在 main 函数中,每隔5分钟获取最新数据,计算指标,检查信号,并执行交易。
请注意,这段代码仅为示例,实际交易时应考虑更多因素,例如交易量、手续费、风控等,后面分两步进行完善。
增加仓位管理逻辑
上述执行交易函数存在明显的漏洞,只有开仓动作,没有平仓动作。所以新增一条交易逻辑:当没有持有信号方向的持仓时才进行开仓;如果有信号方向的持仓就进行平仓。
这就需要增加仓位管理的逻辑,实现获取仓位的接口。
代码实现
import ccxt
import pandas as pd
import ta
import time
# 初始化 Binance 交易所实例
exchange = ccxt.binance({
'apiKey': 'YOUR_API_KEY', # 替换为你的 API Key
'secret': 'YOUR_SECRET_KEY', # 替换为你的 Secret Key
})
# 获取 5 分钟的 K 线数据
def fetch_ohlcv(symbol, timeframe='5m', limit=100):
ohlcv = exchange.fetch_ohlcv(symbol, timeframe, limit=limit)
df = pd.DataFrame(ohlcv, columns=['timestamp', 'open', 'high', 'low', 'close', 'volume'])
df['timestamp'] = pd.to_datetime(df['timestamp'], unit='ms')
df.set_index('timestamp', inplace=True)
return df
# 计算 MACD 指标
def calculate_macd(df):
macd = ta.trend.MACD(df['close'])
df['macd'] = macd.macd()
df['macd_signal'] = macd.macd_signal()
df['macd_diff'] = macd.macd_diff()
# 检查交易信号
def check_trade_signals(df):
last_row = df.iloc[-1]
previous_row = df.iloc[-2]
# 买入条件:MACD 越过零线
if previous_row['macd'] < 0 and last_row['macd'] > 0:
return 'buy'
# 卖出条件:MACD 低于零线
if previous_row['macd'] > 0 and last_row['macd'] < 0:
return 'sell'
return 'hold'
# 获取当前持仓方向和数量
def get_position(symbol):
balance = exchange.fetch_balance()
if symbol in balance['total']:
return balance['total'][symbol]
return 0
# 执行交易
def execute_trade(signal, symbol='BTC/USDT', amount=0.001):
base_currency = symbol.split('/')[0]
position = get_position(base_currency)
if signal == 'buy':
if position <= 0:
order = exchange.create_market_buy_order(symbol, amount)
print('Buy order executed:', order)
else:
print('Already holding a buy position. No action taken.')
elif signal == 'sell':
if position > 0:
order = exchange.create_market_sell_order(symbol, amount)
print('Sell order executed:', order)
else:
print('No buy position to sell. No action taken.')
# 主循环
def main():
symbol = 'BTC/USDT'
while True:
df = fetch_ohlcv(symbol)
calculate_macd(df)
calculate_ema(df)
calculate_kdj(df)
signal = check_trade_signals(df)
execute_trade(signal, symbol)
time.sleep(300) # 每5分钟运行一次
if __name__ == "__main__":
main()
修改说明
1、获取当前持仓方向和数量:添加 get_position 函数,获取当前账户的持仓情况。如果持有目标资产(如 BTC),返回持有数量,否则返回 0。
2、修改交易逻辑:在 execute_trade 函数中,根据信号检查当前持仓:
- 如果是买入信号(‘buy’),且当前没有持有或持有空头仓位,则进行买入操作。
- 如果是卖出信号(‘sell’),且当前持有多头仓位,则进行卖出操作。
3、主循环:保持不变,每隔 5 分钟获取最新数据,计算指标,检查信号,并执行交易。
请注意,这段代码仍然是一个简化的示例。在实际交易中,还需要考虑更多的细节和异常处理,例如 API 调用失败、交易失败、网络问题等。另外,务必在模拟环境中进行充分测试,确保策略的可靠性和安全性。
增加风险控制功能
增加风险控制功能也就是止盈止损的逻辑:
- 持仓盈利超过5%,则平仓
- 持仓亏损超过3%,则平仓
代码实现
import ccxt
import pandas as pd
import ta
import time
# 初始化 Binance 交易所实例
exchange = ccxt.binance({
'apiKey': 'YOUR_API_KEY', # 替换为你的 API Key
'secret': 'YOUR_SECRET_KEY', # 替换为你的 Secret Key
})
# 获取 5 分钟的 K 线数据
def fetch_ohlcv(symbol, timeframe='5m', limit=100):
ohlcv = exchange.fetch_ohlcv(symbol, timeframe, limit=limit)
df = pd.DataFrame(ohlcv, columns=['timestamp', 'open', 'high', 'low', 'close', 'volume'])
df['timestamp'] = pd.to_datetime(df['timestamp'], unit='ms')
df.set_index('timestamp', inplace=True)
return df
# 计算 MACD 指标
def calculate_macd(df):
macd = ta.trend.MACD(df['close'])
df['macd'] = macd.macd()
df['macd_signal'] = macd.macd_signal()
df['macd_diff'] = macd.macd_diff()
# 检查交易信号
def check_trade_signals(df):
last_row = df.iloc[-1]
previous_row = df.iloc[-2]
# 买入条件:MACD 越过零线
if previous_row['macd'] < 0 and last_row['macd'] > 0:
return 'buy'
# 卖出条件:MACD 低于零线
if previous_row['macd'] > 0 and last_row['macd'] < 0:
return 'sell'
return 'hold'
# 获取当前持仓方向和数量
def get_position(symbol):
balance = exchange.fetch_balance()
base_currency = symbol.split('/')[0]
if base_currency in balance['total']:
return balance['total'][base_currency]
return 0
# 计算持仓盈亏比例
def calculate_profit_loss(entry_price, current_price):
return (current_price - entry_price) / entry_price
# 执行交易
def execute_trade(signal, symbol='BTC/USDT', amount=0.001, entry_price=None):
base_currency = symbol.split('/')[0]
position = get_position(symbol)
if signal == 'buy':
if position <= 0:
order = exchange.create_market_buy_order(symbol, amount)
print('Buy order executed:', order)
entry_price = order['price']
else:
print('Already holding a buy position. No action taken.')
elif signal == 'sell':
if position > 0:
order = exchange.create_market_sell_order(symbol, amount)
print('Sell order executed:', order)
entry_price = None
else:
print('No buy position to sell. No action taken.')
# 止盈止损逻辑
if entry_price:
ticker = exchange.fetch_ticker(symbol)
current_price = ticker['last']
profit_loss_ratio = calculate_profit_loss(entry_price, current_price)
if profit_loss_ratio >= 0.05: # 止盈条件
if position > 0:
order = exchange.create_market_sell_order(symbol, amount)
print('Take profit order executed:', order)
entry_price = None
elif profit_loss_ratio <= -0.03: # 止损条件
if position > 0:
order = exchange.create_market_sell_order(symbol, amount)
print('Stop loss order executed:', order)
entry_price = None
# 主循环
def main():
symbol = 'BTC/USDT'
entry_price = None
while True:
df = fetch_ohlcv(symbol)
calculate_macd(df)
calculate_ema(df)
calculate_kdj(df)
signal = check_trade_signals(df)
execute_trade(signal, symbol, entry_price=entry_price)
time.sleep(300) # 每5分钟运行一次
if __name__ == "__main__":
main()
修改说明
1、计算持仓盈亏比例:添加 calculate_profit_loss 函数,计算当前持仓的盈亏比例。
2、止盈止损逻辑:在 execute_trade 函数中,添加止盈和止损逻辑:
- 如果当前持仓的盈利比例大于等于 5% (profit_loss_ratio >= 0.05),则执行止盈平仓操作。
- 如果当前持仓的亏损比例小于等于 -3% (profit_loss_ratio <= -0.03),则执行止损平仓操作。
3、更新 execute_trade 函数:在买入和卖出操作中记录或清除 entry_price,以便在止盈止损逻辑中使用。
4、主循环中传递 entry_price:在 main 函数中,每次调用 execute_trade 函数时传递 entry_price 参数。
如果说还要继续优化的话,可能增加动态止盈的功能,后面有时间在进一步优化。