跳转至

均线交叉

5 日均线上穿 20 日均线买入,下穿卖出。经典的趋势跟踪策略。


单股票

"""5 日线上穿 20 日线买入,下穿卖出"""
from qka import Data, Strategy, Broker, Backtest


class MaCross(Strategy):
    def __init__(self, cash=100_000):
        super().__init__(cash=cash)

    def on_bar(self, date):
        close = self.get('close')
        if close is None or close.empty:
            return
        if '000001.SZ' not in close.index:
            return

        # 取历史均线
        ma5 = self.history('sma_5', 3)
        ma20 = self.history('sma_20', 3)

        if len(ma5) < 2 or len(ma20) < 2:
            return

        price = float(close['000001.SZ'])
        if price <= 0:
            return

        # 今日 5 日线 > 20 日线,且昨天 5 日线 <= 20 日线(上穿)
        if (ma5['000001.SZ'].iloc[-1] > ma20['000001.SZ'].iloc[-1] and
            ma5['000001.SZ'].iloc[-2] <= ma20['000001.SZ'].iloc[-2]):

            if '000001.SZ' not in self.broker.positions:
                size = self.sizing.percent(0.5, price)
                if size > 0:
                    self.broker.buy('000001.SZ', price, size)

        # 下穿卖出
        elif (ma5['000001.SZ'].iloc[-1] < ma20['000001.SZ'].iloc[-1] and
              ma5['000001.SZ'].iloc[-2] >= ma20['000001.SZ'].iloc[-2]):

            if '000001.SZ' in self.broker.positions:
                pos = self.broker.positions['000001.SZ']
                self.broker.sell('000001.SZ', price, pos['size'])


if __name__ == '__main__':
    data = Data(
        symbols=['000001.SZ'],
        indicators={
            'sma_5': ('sma', 5),
            'sma_20': ('sma', 20),
        },
    )
    bt = Backtest(data, MaCross())
    bt.run(benchmark='000300.SH')
    bt.summary()
    bt.report(title='均线交叉 - 平安银行')

多股票

每只股票独立判断,谁出信号买谁:

"""多股票均线交叉,每只股票判断自己的信号"""
from qka import Data, Strategy, Broker, Backtest


class MultiMaCross(Strategy):
    def __init__(self, cash=1_000_000):
        super().__init__(cash=cash)

    def on_bar(self, date):
        close = self.get('close')
        if close is None or close.empty:
            return

        # 取历史均线(多股票的 DataFrame)
        ma5 = self.history('sma_5', 3)
        ma20 = self.history('sma_20', 3)

        if len(ma5) < 2 or len(ma20) < 2:
            return

        for sym in close.index:
            price = float(close[sym])
            if price <= 0:
                continue
            if sym not in ma5.columns or sym not in ma20.columns:
                continue

            # 上穿买入
            if (ma5[sym].iloc[-1] > ma20[sym].iloc[-1] and
                ma5[sym].iloc[-2] <= ma20[sym].iloc[-2]):

                if sym not in self.broker.positions:
                    size = self.sizing.percent(0.1, price)
                    if size > 0:
                        self.broker.buy(sym, price, size)

            # 下穿卖出
            elif (ma5[sym].iloc[-1] < ma20[sym].iloc[-1] and
                  ma5[sym].iloc[-2] >= ma20[sym].iloc[-2]):

                if sym in self.broker.positions:
                    pos = self.broker.positions[sym]
                    self.broker.sell(sym, price, pos['size'])


if __name__ == '__main__':
    data = Data(
        symbols=['000001.SZ', '600000.SH', '000002.SZ'],
        indicators={
            'sma_5': ('sma', 5),
            'sma_20': ('sma', 20),
        },
    )
    bt = Backtest(data, MultiMaCross())
    bt.run(benchmark='000300.SH')
    bt.summary()
    bt.report(title='多股票均线交叉')