Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Strategy with Signals

Operatingbacktrader is also possible without having to write aStrategy. Although this is the preferred way, due to the object hierarchywhich makes up the machinery, usingSignals is also possible.

Quick summary:

  • Instead of writing aStrategy class, instantiatingIndicators, writing thebuy/sell logic …

  • The end user addSignals (indicators anyhow) and the rest is done in the background

Quick example:

importbacktraderasbtdata=bt.feeds.OneOfTheFeeds(dataname='mydataname')cerebro.adddata(data)cerebro.add_signal(bt.SIGNAL_LONGSHORT,MySignal)cerebro.run()

Et voilá!.

Of course theSignal itself is missing. Let’s define a very dumbSignalwhich yields:

  • Long indication if theclose price is above aSimple Moving Average

  • Short indication if theclose price is below aSimple Moving Average

The definition:

classMySignal(bt.Indicator):lines=('signal',)params=(('period',30),)def__init__(self):self.lines.signal=self.data-bt.indicators.SMA(period=self.p.period)

And now it is really done. Whenrun is executedCerebro will take care ofinstantiating a specialStrategy instance which knows what to do with theSignals.

InitialFAQ

  • How is the volume ofbuy/sell operations determined?

    Acerebro instance adds automatically aFixedSize sizer tostrategies. The end user can change the sizer to alter the policy withcerebro.addsizer

  • How are orders executed?

    The execution type isMarket and the validity isGood Until Canceled

Signals technicalities

From a technical and theoretical point of view can be as described:

  • A callable that returns anotherobject when called (only once)

    This is in most cases the instantiation of a class, but must not be

  • Supports the__getitem__ interface. The only requestedkey/index will be0

From a practical point of view and looking at the example above aSignal is:

  • Alines object from thebacktrader ecosystem, mostly anIndicator

    This helps when using otherIndicators like when in the example theSimpleMoving Average is used.

Signals indications

Thesignals delivers indications when queried withsignal[0] and themeaning is:

  • > 0 ->long indication

  • < 0 ->short indication

  • == 0 ->No indication

The example does simple arithmetic withself.data - SMA and:

  • Issues along indication when thedata is above theSMA

  • Issues ashort indication when thedata is below theSMA

Note

When no specific price field is indicated for thedata, theclose price is the reference price is.

Signals Types

Theconstants indicated below as seen in the example above, are directlyavailable from the mainbacktrader module as in:

importbacktraderasbtbt.SIGNAL_LONG

There are 5 types ofSignals, broken in 2 groups.

Main Group:

  • LONGSHORT: bothlong andshort indications from this signal are taken

  • LONG:

    • long indications are taken to go long

    • short indications are taken toclose the long position. But:

    • If aLONGEXIT (see below) signal is in the system it will be used to exit the long

    • If aSHORT signal is available and noLONGEXIT is available , it will be used to close along before opening ashort

  • SHORT:

    • short indications are taken to go short

    • long indications are taken toclose the short position. But:

    • If aSHORTEXIT (see below) signal is in the system it will be used to exit the short

    • If aLONG signal is available and noSHORTEXIT is available , it will be used to close ashort before opening along

Exit Group:

This 2 signals are meant to override others and provide criteria for exitins along /short position

  • LONGEXIT:short indications are taken to exitlong positions

  • SHORTEXIT:long indications are taken to exitshort positions

Accumulation and Order Concurrency

The sampleSignal shown above will issuelong andshort indications on aconstant basis, because it simply substracts theSMA value from theclose price and this will always be either> 0 and< 0 (0 ismathematically possible, but unlikely to really happen)

This would lead to a continuous generation oforders that would produce 2situations:

  • Accumulation: even if already in the market, thesignals would produce new orders which would increase the possition in the market

  • Concurrency: new orders would be generated without waiting for the execution of other orders

To avoid this the default behavior is:

  • To Not Accumulate

  • To Not allow Concurrency

Should any of these two behaviors be wished, this can be controlled viacerebro with:

  • cerebro.signal_accumulate(True) (orFalse to re-disable it)

  • cerebro.signal_concurrency(True) (orFalse to re-disable it)

The sample

Thebacktrader sources contain a sample to test the functionality.

Main signal to be used.

classSMACloseSignal(bt.Indicator):lines=('signal',)params=(('period',30),)def__init__(self):self.lines.signal=self.data-bt.indicators.SMA(period=self.p.period)

And theExit Signal in case the option is specified.

classSMAExitSignal(bt.Indicator):lines=('signal',)params=(('p1',5),('p2',30),)def__init__(self):sma1=bt.indicators.SMA(period=self.p.p1)sma2=bt.indicators.SMA(period=self.p.p2)self.lines.signal=sma1-sma2

First run: long and short

$ ./signals-strategy.py --plot --signal longshort

The output

image

To notice:

  • TheSignal is plotted. This is normal given it is simply an indicator and the plotting rules for it apply

  • The strategy is reallylong andshort. This can be seen because thecash level never goes back to be thevalue level

  • Side note: even for a dumb idea … (and without commission) the strategy hasn’t lost money …

Second run: long only

$ ./signals-strategy.py --plot --signal longonly

The output

image

To notice:

  • Here the cash level goes back to be thevalue level after eachsell, which means the strategy is out of the market

  • Side note: Again no money has been lost …

Third run: short only

$ ./signals-strategy.py --plot --signal shortonly

The output

image

To notice:

  • The 1st operation is asell as expected and takes place later than the 1st operation in the 2 examples above. Not until theclose is below theSMA and the simple substraction yields a minus

  • Here the cash level goes back to be thevalue level after eachbuy, which means the strategy is out of the market

  • Side note: Finally the system loses money

Fourth run: long + longexit

$ ./signals-strategy.py --plot --signal longonly --exitsignal longexit

The output

image

To notice:

  • Many of the trades are the same, but some are interrupted earlier because the fast moving average in theexit signal crosses the slow moving average to the downside

  • The system shows itslongonly property with the cash becoming the value at the end of each trade

  • Side note: Again money is made … even with some modified trades

Usage

$ ./signals-strategy.py --helpusage: signals-strategy.py [-h] [--data DATA] [--fromdate FROMDATE]                           [--todate TODATE] [--cash CASH]                           [--smaperiod SMAPERIOD] [--exitperiod EXITPERIOD]                           [--signal {longshort,longonly,shortonly}]                           [--exitsignal {longexit,shortexit}]                           [--plot [kwargs]]Sample for Signal conceptsoptional arguments:  -h, --help            show this help message and exit  --data DATA           Specific data to be read in (default:                        ../../datas/2005-2006-day-001.txt)  --fromdate FROMDATE   Starting date in YYYY-MM-DD format (default: None)  --todate TODATE       Ending date in YYYY-MM-DD format (default: None)  --cash CASH           Cash to start with (default: 50000)  --smaperiod SMAPERIOD                        Period for the moving average (default: 30)  --exitperiod EXITPERIOD                        Period for the exit control SMA (default: 5)  --signal {longshort,longonly,shortonly}                        Signal type to use for the main signal (default:                        longshort)  --exitsignal {longexit,shortexit}                        Signal type to use for the exit signal (default: None)  --plot [kwargs], -p [kwargs]                        Plot the read data applying any kwargs passed For                        example: --plot style="candle" (to plot candles)                        (default: None)

The code

from__future__import(absolute_import,division,print_function,unicode_literals)importargparseimportcollectionsimportdatetimeimportbacktraderasbtMAINSIGNALS=collections.OrderedDict((('longshort',bt.SIGNAL_LONGSHORT),('longonly',bt.SIGNAL_LONG),('shortonly',bt.SIGNAL_SHORT),))EXITSIGNALS={'longexit':bt.SIGNAL_LONGEXIT,'shortexit':bt.SIGNAL_LONGEXIT,}classSMACloseSignal(bt.Indicator):lines=('signal',)params=(('period',30),)def__init__(self):self.lines.signal=self.data-bt.indicators.SMA(period=self.p.period)classSMAExitSignal(bt.Indicator):lines=('signal',)params=(('p1',5),('p2',30),)def__init__(self):sma1=bt.indicators.SMA(period=self.p.p1)sma2=bt.indicators.SMA(period=self.p.p2)self.lines.signal=sma1-sma2defrunstrat(args=None):args=parse_args(args)cerebro=bt.Cerebro()cerebro.broker.set_cash(args.cash)dkwargs=dict()ifargs.fromdateisnotNone:fromdate=datetime.datetime.strptime(args.fromdate,'%Y-%m-%d')dkwargs['fromdate']=fromdateifargs.todateisnotNone:todate=datetime.datetime.strptime(args.todate,'%Y-%m-%d')dkwargs['todate']=todate# if dataset is None, args.data has been givendata=bt.feeds.BacktraderCSVData(dataname=args.data,**dkwargs)cerebro.adddata(data)cerebro.add_signal(MAINSIGNALS[args.signal],SMACloseSignal,period=args.smaperiod)ifargs.exitsignalisnotNone:cerebro.add_signal(EXITSIGNALS[args.exitsignal],SMAExitSignal,p1=args.exitperiod,p2=args.smaperiod)cerebro.run()ifargs.plot:pkwargs=dict(style='bar')ifargs.plotisnotTrue:# evals to True but is not Truenpkwargs=eval('dict('+args.plot+')')# args were passedpkwargs.update(npkwargs)cerebro.plot(**pkwargs)defparse_args(pargs=None):parser=argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter,description='Sample for Signal concepts')parser.add_argument('--data',required=False,default='../../datas/2005-2006-day-001.txt',help='Specific data to be read in')parser.add_argument('--fromdate',required=False,default=None,help='Starting date in YYYY-MM-DD format')parser.add_argument('--todate',required=False,default=None,help='Ending date in YYYY-MM-DD format')parser.add_argument('--cash',required=False,action='store',type=float,default=50000,help=('Cash to start with'))parser.add_argument('--smaperiod',required=False,action='store',type=int,default=30,help=('Period for the moving average'))parser.add_argument('--exitperiod',required=False,action='store',type=int,default=5,help=('Period for the exit control SMA'))parser.add_argument('--signal',required=False,action='store',default=MAINSIGNALS.keys()[0],choices=MAINSIGNALS,help=('Signal type to use for the main signal'))parser.add_argument('--exitsignal',required=False,action='store',default=None,choices=EXITSIGNALS,help=('Signal type to use for the exit signal'))# Plot optionsparser.add_argument('--plot','-p',nargs='?',required=False,metavar='kwargs',const=True,help=('Plot the read data applying any kwargs passed\n''\n''For example:\n''\n''  --plot style="candle" (to plot candles)\n'))ifpargsisnotNone:returnparser.parse_args(pargs)returnparser.parse_args()if__name__=='__main__':runstrat()

[8]ページ先頭

©2009-2025 Movatter.jp