Skip to main content

送出訂單

此文章內容為策略開發教學,不代表任何投資建議

在上一篇教學裡面,我們成功取得 K 線資料,這篇教學中我們將利用歷史資料作為買賣依據,並送出訂單。

計算移動平均#

以移動平均為例,我們將長、短週期移動平均線的黃金交叉與死亡交叉作為買進、賣出點。

__init__ 中設定長週期為 10、短週期為 5。

self.long_window_size = 10
self.short_window_size = 5

將歷史收盤價存入 close_price_history 用來計算移動平均。

當資料不足時 talib 會得到 NaN,無法判斷黃金交叉或死亡交叉,直接返回不交易。

def trade(self, candles):
exchange, pair, base, quote = CA.get_exchange_pair()
# get the latest 10 candles
if len(candles[exchange][pair]) < self.long_window_size + 1:
return
candles[exchange][pair] = candles[exchange][pair][:self.long_window_size + 1]
# use close price
close_price_history = [candle['close'] for candle in candles[exchange][pair]]

candles 是由新到舊排列,而 talib 接受的輸入為舊到新排列,因此將資料進行反轉。

# convert to chronological order for talib
close_price_history.reverse()

轉換成 talib 接受的 np.array,並使用 talib 計算得到長、短週期的移動平均歷史。

# convert np.array
close_price_history = np.array(close_price_history)
long_ma_history = talib.SMA(close_price_history, self.long_window_size)
short_ma_history = talib.SMA(close_price_history, self.short_window_size)

送出訂單#

取得可用資產數量。

# get available balance
base_balance = CA.get_balance(exchange, base)
quote_balance = CA.get_balance(exchange, quote)
available_base_amount = base_balance.available
available_quote_amount = quote_balance.available

根據 long_ma_history, short_ma_history 最後兩筆資料判斷黃金交叉、死亡交叉,並檢查資產後送出訂單。

if short_ma_history[-2] < long_ma_history[-2] and short_ma_history[-1] > long_ma_history[-1]:
CA.log('黃金交叉')
amount = 0.1
if available_quote_amount >= amount * close_price_history[-1]:
CA.log('買入 ' + base)
CA.buy(exchange, pair, amount, CA.OrderType.MARKET)
else:
CA.log('資產不足')
elif short_ma_history[-2] > long_ma_history[-2] and short_ma_history[-1] < long_ma_history[-1]:
CA.log('死亡交叉')
if available_base_amount > 0:
CA.log('賣出 ' + base)
CA.sell(exchange, pair, available_base_amount, CA.OrderType.MARKET)
else:
CA.log('資產不足')

完整程式碼#

class Strategy(StrategyBase):
def __init__(self):
# strategy attributes
self.period = 60 * 60
self.subscribed_books = {
'Binance': {
'pairs': ['ETH-USDT'],
},
}
self.options = {}
# define your attributes here
self.long_window_size = 10
self.short_window_size = 5
def on_order_state_change(self, order):
pass
def trade(self, candles):
exchange, pair, base, quote = CA.get_exchange_pair()
# get the latest 10 candles
if len(candles[exchange][pair]) < self.long_window_size + 1:
return
candles[exchange][pair] = candles[exchange][pair][:self.long_window_size + 1]
# use close price
close_price_history = [candle['close'] for candle in candles[exchange][pair]]
# convert to chronological order for talib
close_price_history.reverse()
# convert np.array
close_price_history = np.array(close_price_history)
long_ma_history = talib.SMA(close_price_history, self.long_window_size)
short_ma_history = talib.SMA(close_price_history, self.short_window_size)
# get available balance
base_balance = CA.get_balance(exchange, base)
quote_balance = CA.get_balance(exchange, quote)
available_base_amount = base_balance.available
available_quote_amount = quote_balance.available
if short_ma_history[-2] < long_ma_history[-2] and short_ma_history[-1] > long_ma_history[-1]:
CA.log('黃金交叉')
amount = 0.1
if available_quote_amount >= amount * close_price_history[-1]:
CA.log('買入 ' + base)
CA.buy(exchange, pair, amount, CA.OrderType.MARKET)
else:
CA.log('資產不足')
elif short_ma_history[-2] > long_ma_history[-2] and short_ma_history[-1] < long_ma_history[-1]:
CA.log('死亡交叉')
if available_base_amount > 0:
CA.log('賣出 ' + base)
CA.sell(exchange, pair, available_base_amount, CA.OrderType.MARKET)
else:
CA.log('資產不足')