class SingleMA(strategy.BacktestingStrategy): def __init__(self, feed, instrument, n, initialCash=1000000): strategy.BacktestingStrategy.__init__(self, feed, initialCash) self.__instrument = instrument self.getBroker().setFillStrategy(DefaultStrategy(None)) self.getBroker().setCommission(TradePercentage(0.001)) self.__position = None self.__prices = feed[instrument].getPriceDataSeries() self.__malength = int(n) self.__ma = ma.SMA(self.__prices, self.__malength) self.__pos = SequenceDataSeries() # record signal def getPrice(self): return self.__prices def getMA(self): return self.__ma def testCon(self): if self.__position is not None: self.__pos.append(1) elif self.__position is None: self.__pos.append(0) def getPos(self): return self.__pos def onEnterCanceled(self, position): self.__position = None def onEnterOk(self, position): execInfo = position.getEntryOrder().getExecutionInfo() instrumentInfo = position.getInstrument() self.info("BUY %s at $%.2f" % (instrumentInfo, execInfo.getPrice())) def onExitOk(self, position): execInfo = position.getExitOrder().getExecutionInfo() instrumentInfo = position.getInstrument() self.info("SELL %s at $%.2f" % (instrumentInfo, execInfo.getPrice())) self.__position = None def onExitCancelled(self, position): self.__position.exitMarket() def onBars(self, bars): closePrice = bars[self.__instrument].getPrice() if self.__ma[-1] is None: return self.testCon() if self.__position is not None: if not self.__position.exitActive() and closePrice < self.__ma[-1]: self.__position.exitMarket() if self.__position is None: if closePrice > self.__ma[-1]: shares = int(self.getBroker().getEquity() * 0.9 / closePrice) self.__position = self.enterLong(self.__instrument, shares)
def __init__(self, feed, instrument, n, initialCash=1000000): strategy.BacktestingStrategy.__init__(self, feed, initialCash) self.__instrument = instrument self.getBroker().setFillStrategy(DefaultStrategy(None)) self.getBroker().setCommission(TradePercentage(0.001)) self.__position = None self.__prices = feed[instrument].getPriceDataSeries() self.__malength = int(n) self.__ma = ma.SMA(self.__prices, self.__malength) self.__pos = SequenceDataSeries() # record signal
def __init__(self, feed, instrument, mall, mals, masl, mass): strategy.BacktestingStrategy.__init__(self, feed) self.getBroker().setFillStrategy(DefaultStrategy(None)) self.getBroker().setCommission(TradePercentage(0.001)) self.__instrument = instrument self.__close = feed[instrument].getCloseDataSeries() self.__longPos = None self.__shortPos = None self.__mall = ma.SMA(self.__close, int(mall)) self.__mals = ma.SMA(self.__close, int(mals)) self.__masl = ma.SMA(self.__close, int(masl)) self.__mass = ma.SMA(self.__close, int(mass)) self.__position = SequenceDataSeries()
def __init__(self, feed, instrument, n, initialCash = 1000000): strategy.BacktestingStrategy.__init__(self, feed, initialCash) self.__instrument = instrument self.getBroker().setFillStrategy(DefaultStrategy(None)) self.getBroker().setCommission(TradePercentage(0.001)) self.__position = None self.__prices = feed[instrument].getPriceDataSeries() self.__malength = int(n) self.__ma = ma.SMA(self.__prices, self.__malength) self.__pos = SequenceDataSeries() # record signal
def __init__(self, feed, instrument, fast, slow, signal, up_cum): strategy.BacktestingStrategy.__init__(self, feed) self.__instrument = instrument self.getBroker().setFillStrategy(DefaultStrategy(None)) self.getBroker().setCommission(TradePercentage(0.0008)) self.__longPos = None self.__shortPos = None self.__prices = feed[instrument].getPriceDataSeries() self.__macd=macd.MACD(self.__prices,fast,slow,signal) self.__range=0 self.__circ = int(up_cum) self.__position = SequenceDataSeries()
def __init__(self, instrument, dataSeries, fastEMA, slowEMA, signalEMA, maxLen=None): assert (fastEMA > 0) assert (slowEMA > 0) assert (fastEMA < slowEMA) assert (signalEMA > 0) super(Macd, self).__init__(maxLen) self.__instrument = instrument self.__skipNum = max(fastEMA, slowEMA, signalEMA) self.__fastEMAWindow = EMAEventWindow(fastEMA) self.__slowEMAWindow = EMAEventWindow(slowEMA) self.__signalEMAWindow = EMAEventWindow(signalEMA) self.__signal = SequenceDataSeries(maxLen) #dea self.__histogram = SequenceDataSeries(maxLen) #macd self.__cross = SequenceDataSeries( maxLen) #dead cross signals and gold cross signals self.__close_prices = dataSeries.getPriceDataSeries() self.top_divergences = list() self.double_top_divergences = list() self.bottom_divergences = list() self.double_bottom_divergences = list() self.cross_detect = CrossDetect() self.max_limit_detect = MaxLimitDetect self.min_limit_detect = MinLimitDetect self.top_divergence_detect = TopDivergenceDetect() self.bottom_divergence_detect = BottomDivergenceDetect() self.__close_prices.getNewValueEvent().subscribe(self.__onNewValue)
def __init__(self, feed, instrument, mall, mals, masl, mass): strategy.BacktestingStrategy.__init__(self, feed) self.getBroker().setFillStrategy(DefaultStrategy(None)) self.getBroker().setCommission(TradePercentage(0.001)) self.__instrument = instrument self.__close = feed[instrument].getCloseDataSeries() self.__longPos = None self.__shortPos = None self.__mall = ma.SMA(self.__close, int(mall)) self.__mals = ma.SMA(self.__close, int(mals)) self.__masl = ma.SMA(self.__close, int(masl)) self.__mass = ma.SMA(self.__close, int(mass)) self.__position = SequenceDataSeries()
def __init__(self, feed, instrument, bollingerlength, numStdDev): strategy.BacktestingStrategy.__init__(self, feed) self.getBroker().setFillStrategy(DefaultStrategy(None)) self.getBroker().setCommission(TradePercentage(0)) self.__instrument = instrument self.__bollingerlength = int(bollingerlength) self.__close = feed[instrument].getPriceDataSeries() numStdDev = float(numStdDev) / 10 self.__longPos = [] self.__macd=macd.MACD(self.__close,50,150,10) self.__bollinger = bollinger.BollingerBands(self.__macd, self.__bollingerlength, int(numStdDev)) self.__UpperBand = self.__bollinger.getUpperBand() self.__LowerBand = self.__bollinger.getLowerBand() self.__position = SequenceDataSeries() self.__circ=5
def __init__(self, feed, instrument,longline,shortline,bollingerlength, numStdDev): strategy.BacktestingStrategy.__init__(self, feed) self.getBroker().setFillStrategy(DefaultStrategy(None)) self.getBroker().setCommission(TradePercentage(0.001)) self.__instrument = instrument self.__bollingerlength = int(bollingerlength) self.__close = feed[instrument].getMatchDataSeries() numStdDev = float(numStdDev) / 10 self.__longPos = [] self.__shortPos = [] self.__macd=macd.MACD(self.__close,shortline,longline,10) self.__bollinger = bollinger.BollingerBands(self.__macd, self.__bollingerlength, int(numStdDev)) self.__UpperBand = self.__bollinger.getUpperBand() self.__LowerBand = self.__bollinger.getLowerBand() self.__position = SequenceDataSeries() self.__circ=5 self.__lastLongPos=None self.__lastShortPos=None self.__barNum=0 self.__macdMin=[] self.__macdMax=[]
def __init__(self, feed, instrument,preclose,prehigh,prelow,p1,p2,p3,p4): strategy.BacktestingStrategy.__init__(self, feed) self.getBroker().setFillStrategy(DefaultStrategy(None)) self.getBroker().setCommission(TradePercentage(0.001)) self.__instrument = instrument self.__longPos = [] self.__shortPos = [] self.__position = SequenceDataSeries() self.__prices= feed[instrument].getPriceDataSeries() self.__circ=5 self.__lastLongPos=None self.__lastShortPos=None self.__barNum=0 self.__ssetup=prehigh-p1*(preclose-prelow) self.__senter=((1+p2)/2)*(prehigh+preclose)-p2*prelow self.__benter=((1+p2)/2)*(prelow+preclose)-p2*prehigh self.__bsetup=prelow+p1*(prehigh-preclose) self.__bbreak=self.__ssetup+p3*(self.__ssetup-self.__bsetup) self.__sbreak=self.__bsetup-p3*(self.__ssetup-self.__bsetup) self.__moreSsetup=False self.__lessBsetup=False self.__couldsbreak=True self.__couldbbreak=True self.__p4=p4
def __init__(self, feed = None, instrument = '',shortPeriod = 0,longPeriod = 0,money = None,longAllowed=True,shortAllowed=True): strategy.BacktestingStrategy.__init__(self, feed) self.position_cost = 0 #mid init position value mid_DEFAULT_MAX_LEN = 10 * DEFAULT_MAX_LEN self.__instrument = instrument self.__longPosition = None self.__shortPosition = None self.__position_volume = SequenceDataSeries(maxLen = mid_DEFAULT_MAX_LEN) #mid 当前持有头寸数量 self.__position_cost = SequenceDataSeries(maxLen = mid_DEFAULT_MAX_LEN) #mid 当前持有头寸开仓成本 self.__position_pnl = SequenceDataSeries(maxLen = mid_DEFAULT_MAX_LEN) #mid 当前持有头寸价值 self.__portfolio_value = SequenceDataSeries(maxLen = mid_DEFAULT_MAX_LEN) self.__buy = SequenceDataSeries(maxLen = mid_DEFAULT_MAX_LEN) self.__sell = SequenceDataSeries(maxLen = mid_DEFAULT_MAX_LEN) self.__buySignal = False self.__sellSignal = False self.money = money self.longAllowed = True self.shortAllowed = True #mid 计算ma将使用当天的收盘价格计算 #mid 1) dataSeries = feed[instrument] dataSeries.setMaxLen(mid_DEFAULT_MAX_LEN) closeSeries = dataSeries.getCloseDataSeries() #mid 2) prices = closeSeries prices.setMaxLen(mid_DEFAULT_MAX_LEN) #mid 3) self.__sma = ma.SMA(prices, shortPeriod,maxLen=mid_DEFAULT_MAX_LEN) self.__lma = ma.SMA(prices,longPeriod,maxLen=mid_DEFAULT_MAX_LEN) self.i = 0
class Bollinger_Bandit(strategy.BacktestingStrategy): def __init__(self, feed, instrument, bollingerlength, numStdDev, closelength, ccMAlength, malength, space): strategy.BacktestingStrategy.__init__(self, feed) self.getBroker().setFillStrategy(DefaultStrategy(None)) self.getBroker().setCommission(TradePercentage(0.002)) self.__instrument = instrument self.__bollingerlength = int(bollingerlength) numStdDev = float(numStdDev) / 10 self.__closelength = int(closelength) self.__ccMAlength = int(ccMAlength) self.__malength = int(malength) self.__longPos = None self.__shortPos = None self.__close = feed[instrument].getCloseDataSeries() self.__open = feed[instrument].getOpenDataSeries() self.__high = feed[instrument].getHighDataSeries() self.__low = feed[instrument].getLowDataSeries() self.__datetime = feed[instrument].getDateTimes() self.__bollinger = bollinger.BollingerBands(self.__close, self.__bollingerlength, int(numStdDev)) self.__UpperBand = self.__bollinger.getUpperBand() self.__LowerBand = self.__bollinger.getLowerBand() self.__MA = SequenceDataSeries() self.__space = int(space) self.__enter = 0 self.__enterLong1 = 0 self.__enterLong2 = 0 self.__enterShort1 = 0 self.__enterShort2 = 0 self.__exitLong1 = 0 self.__exitLong2 = 0 self.__exitShort1 = 0 self.__exitShort1 = 0 #for test ######################################################################### self.__p = SequenceDataSeries() self.__filterCon = SequenceDataSeries() self.__ccMACon1 = SequenceDataSeries() self.__ccMACon2 = SequenceDataSeries() self.__enterCon = SequenceDataSeries() self.__enterLongCon1 = SequenceDataSeries() self.__enterLongCon2 = SequenceDataSeries() self.__enterShortCon1 = SequenceDataSeries() self.__enterShortCon2 = SequenceDataSeries() self.__exitLongCon1 = SequenceDataSeries() self.__exitLongCon2 = SequenceDataSeries() self.__exitShortCon1 = SequenceDataSeries() self.__exitShortCon2 = SequenceDataSeries() ########################################################################## def getHigh(self): return self.__high def getLow(self): return self.__low def getClose(self): return self.__close def getBollinger(self): return self.__UpperBand, self.__LowerBand def getMA(self): return self.__MA def getDateTime(self): return self.__datetime def getPosition(self): return self.__p def getTest(self): return self.__filterCon, self.__ccMACon1, self.__ccMACon2, \ self.__enterCon, self.__enterLongCon1, self.__enterLongCon2, self.__enterShortCon1, \ self.__enterShortCon2, self.__exitLongCon1, self.__exitLongCon2, \ self.__exitShortCon1, self.__exitShortCon2 def onEnterCanceled(self, position): if self.__longPos == position: self.__longPos = None elif self.__shortPos == position: self.__shortPos = None else: assert (False) def onExitOk(self, position): if self.__longPos == position: self.__longPos = None elif self.__shortPos == position: self.__shortPos = None else: assert (False) def onBars(self, bars): # If a position was not opened, check if we should enter a long position. bar = bars[self.__instrument] if len(self.__high) > 1: print self.__close[-1], self.__high[-1], self.__open[ -1], self.__close[-2] if self.__UpperBand is not None: print self.__UpperBand[-1] # filter datetime ################################################################################### filterCon = len(self.__close) < max( self.__bollingerlength, self.__malength, self.__closelength) self.__filterCon.append(filterCon) if filterCon: return # record position #################################################################################### if self.__longPos is not None and self.__shortPos is None: self.__p.append(1) elif self.__longPos is None and self.__shortPos is not None: self.__p.append(-1) else: self.__p.append(0) # calculate ccMA #################################################################################### ccMACon1 = self.__longPos is not None or self.__shortPos is not None ccMACon2 = self.__malength > self.__ccMAlength if ccMACon1 and ccMACon2: self.__malength = self.__malength - 1 elif not ccMACon1: self.__malength = 50 self.__ccMA = np.mean(self.__close[-self.__malength:]) # print self.__malength, self.__ccMA self.__MA.append(self.__ccMA) self.__ccMACon1.append(ccMACon1) self.__ccMACon2.append(ccMACon2) #open and close condition ###################################################################################### self.__enterLong1 = (cross.cross_above(self.__high, self.__UpperBand) > 0) self.__enterLong2 = (bar.getClose() >= max( self.__close[-self.__closelength:])) self.__enter = ((self.__UpperBand[-1] - self.__LowerBand[-1]) / bar.getClose() > float(self.__space) / 1000) # print (self.__UpperBand[-1] - self.__LowerBand[-1]) / bar.getClose() self.__enterShort1 = cross.cross_below(self.__low, self.__LowerBand) > 0 self.__enterShort2 = bar.getClose() <= min( self.__close[-self.__closelength:]) self.__exitLong1 = (bar.getClose() < self.__ccMA) self.__exitLong2 = (self.__ccMA < self.__UpperBand[-1]) self.__exitShort1 = (bar.getClose() > self.__ccMA) self.__exitShort2 = (self.__ccMA > self.__LowerBand[-1]) self.__enterCon.append(self.__enter) self.__enterLongCon1.append(self.__enterLong1) self.__enterLongCon2.append(self.__enterLong2) self.__enterShortCon1.append(self.__enterShort1) self.__enterShortCon2.append(self.__enterShort2) self.__exitLongCon1.append(self.__exitLong1) self.__exitLongCon2.append(self.__exitLong2) self.__exitShortCon1.append(self.__exitShort1) self.__exitShortCon2.append(self.__exitShort2) #open and close ####################################################################################### if self.__longPos is not None: if self.exitLongSignal(): self.__longPos.exitMarket() if self.__shortPos is not None: print 11 self.info("intend long close") print(self.__UpperBand[-1] - self.__LowerBand[-1]) / bar.getClose() elif self.__shortPos is not None: if self.exitShortSignal(): self.__shortPos.exitMarket() self.info("intend short close") print(self.__UpperBand[-1] - self.__LowerBand[-1]) / bar.getClose() else: if self.enterLongSignal(): shares = int(self.getBroker().getCash() * 0.2 / bars[self.__instrument].getPrice()) self.__longPos = self.enterLong(self.__instrument, shares) self.info("intend long open") print(self.__UpperBand[-1] - self.__LowerBand[-1]) / bar.getClose() elif self.enterShortSignal(): shares = int(self.getBroker().getCash() * 0.2 / bars[self.__instrument].getPrice()) self.__shortPos = self.enterShort(self.__instrument, shares) self.info("intend short open") print(self.__UpperBand[-1] - self.__LowerBand[-1]) / bar.getClose() def enterLongSignal(self): if self.__enterLong1 and self.__enterLong2 and self.__enter: return True def enterShortSignal(self): if self.__enterShort1 and self.__enterShort2 and self.__enter: return True def exitLongSignal(self): if self.__exitLong1 and self.__exitLong2 and not self.__longPos.exitActive( ): return True def exitShortSignal(self): if self.__exitShort1 and self.__exitShort2 and not self.__shortPos.exitActive( ): return True
class rbreaker(strategy.BacktestingStrategy): def __init__(self, feed, instrument,preclose,prehigh,prelow,p1,p2,p3,p4): strategy.BacktestingStrategy.__init__(self, feed) self.getBroker().setFillStrategy(DefaultStrategy(None)) self.getBroker().setCommission(TradePercentage(0.001)) self.__instrument = instrument self.__longPos = [] self.__shortPos = [] self.__position = SequenceDataSeries() self.__prices= feed[instrument].getPriceDataSeries() self.__circ=5 self.__lastLongPos=None self.__lastShortPos=None self.__barNum=0 self.__ssetup=prehigh-p1*(preclose-prelow) self.__senter=((1+p2)/2)*(prehigh+preclose)-p2*prelow self.__benter=((1+p2)/2)*(prelow+preclose)-p2*prehigh self.__bsetup=prelow+p1*(prehigh-preclose) self.__bbreak=self.__ssetup+p3*(self.__ssetup-self.__bsetup) self.__sbreak=self.__bsetup-p3*(self.__ssetup-self.__bsetup) self.__moreSsetup=False self.__lessBsetup=False self.__couldsbreak=True self.__couldbbreak=True self.__p4=p4 def testCon(self): # record position ####################################################################### if len(self.__longPos) > 0: self.__position.append(len(self.__longPos)) if len(self.__shortPos)>0 : #print(self.__shortPos.getShares()) self.__position.append(-len(self.__shortPos)) elif len(self.__longPos)==0 and len(self.__shortPos)==0: self.__position.append(0) #print(0) def getPrice(self): return self.__prices def getTest(self): return self.__position def onBars(self, bars): bar = bars[self.__instrument] if self.__prices[-1]>self.__ssetup: self.__moreSsetup=True else: self.__couldbbreak=True if self.__prices[-1]<self.__bsetup: self.__lessBsetup=True else: self.__couldsbreak=True dt=bars.getDateTime() h=dt.hour m=dt.minute if(h==14 and m>50): if len(self.__longPos)> 0: for item in self.__longPos: if item[0]._Position__exitOrder is None: item[0].exitMarket() if len(self.__shortPos)>0: for item in self.__shortPos: if item[0]._Position__exitOrder is None: item[0].exitMarket() return self.testCon() if len(self.__longPos)> 0: if self.exitLongSignal(): for item in self.__longPos: if item[0]._Position__exitOrder is None: item[0].exitMarket() elif len(self.__shortPos)>0: if self.exitShortSignal(): for item in self.__shortPos: if item[0]._Position__exitOrder is None: item[0].exitMarket() if self.enterLongSignal(): for i in range(self.enterLongSignal()): shares = int(self.getBroker().getEquity() * 0.2 / bars[self.__instrument].getPrice()) # self.__longPos. pos=self.enterLong(self.__instrument, shares) #pos.exitLimit(bars[self.__instrument].getPrice()*0.99) self.__longPos.append([pos,0]) self.__lastLongPos=self.__barNum #print('long'+str(shares)) if self.enterShortSignal(): for i in range(self.enterShortSignal()): shares = int(self.getBroker().getEquity() * 0.2 / bars[self.__instrument].getPrice()) pos=self.enterShort(self.__instrument, shares) #pos.exitLimit(bars[self.__instrument].getPrice()*1.01) self.__shortPos.append([pos,0]) self.__lastShortPos=self.__barNum def enterLongSignal (self) : if len(self.__longPos)>=2: if self.__lessBsetup: if self.__prices[-1]<self.__benter: return 1 if self.__couldbbreak: if self.__prices[-1]>self.__bbreak: return 1 def enterShortSignal(self) : if len(self.__shortPos)<=2: if self.__moreSsetup: if self.__prices[-1]<self.__senter: return 1 if self.__couldsbreak: if self.__prices[-1]<self.__sbreak: return 1 def exitLongSignal(self) : for item in self.__longPos: print(item[1]) if item[0].getReturn()>item[1]: item[1]=item[0].getReturn() if item[1]-item[0].getReturn()>self.__p4: self.__couldbbreak=False return 1 def exitShortSignal(self): for item in self.__shortPos: if item[0].getReturn()>item[1]: item[1]=item[0].getReturn() if item[1]-item[0].getReturn()>self.__p4: self.__couldsbreak=False return 1 def onEnterCanceled(self, position): if len(self.__longPos)>0: if self.__longPos[-1] == position: del self.__longPos[-1] self.__lastLongPos==None if len(self.__shortPos)>0: if self.__shortPos[-1] == position: del self.__shortPos[-1] self.__lastShortPos==None def onEnterOK(self,position): pass def onExitOk(self, position): if isinstance(position,LongPosition): self.__longPos = [] elif isinstance(position,ShortPosition): self.__shortPos = [] else: assert(False) def onExitCanceled(self, position): position.exitMarket() def getParams(self): return (self.__bbreak,self.__ssetup,self.__senter,self.__benter,self.__bsetup,self.__sbreak)
class thrSMA(strategy.BacktestingStrategy): def __init__(self, feed, instrument, fast, slow, signal, up_cum): strategy.BacktestingStrategy.__init__(self, feed) self.__instrument = instrument self.getBroker().setFillStrategy(DefaultStrategy(None)) self.getBroker().setCommission(TradePercentage(0.0008)) self.__longPos = None self.__shortPos = None self.__prices = feed[instrument].getPriceDataSeries() self.__macd=macd.MACD(self.__prices,fast,slow,signal) self.__range=0 self.__circ = int(up_cum) self.__position = SequenceDataSeries() def getPrice(self): return self.__prices def getMACD(self): return self.__macd def testCon(self): # record position ####################################################################### if self.__longPos is not None: self.__position.append(1) if self.__shortPos is not None: self.__position.append(-1) elif self.__longPos is None and self.__shortPos is None: self.__position.append(0) def getTest(self): return self.__position def onEnterCanceled(self, position): if self.__longPos == position: self.__longPos = None elif self.__shortPos == position: self.__shortPos = None else: assert(False) def onEnterOK(self): pass def onExitOk(self, position): if self.__longPos == position: self.__longPos = None elif self.__shortPos == position: self.__shortPos = None else: assert(False) def onExitCanceled(self, position): position.exitMarket() def buyCon1(self): if self.__macd[-1] < -self.__range: #print(self.__macd[-1]) return True else: return False def buyCon2(self): if self.__macd[-1-self.__circ] is None: return False m1 = 0 for i in range(self.__circ): if self.__macd[-i-1] > self.__macd[-i-2]: m1 += 1 if m1 >= self.__circ: return True else: return False def exitLongCon1(self): if self.__macd[-1]>0: return True else: return False def exitLongCon2(self): if self.__macd[-1-self.__circ] is None: return False m1 = 0 for i in range(self.__circ): if self.__macd[-i-1] < self.__macd[-i-2]: m1 += 1 if m1 >= self.__circ: return True else: return False def exitShortCon1(self): if self.__macd[-1]<0: return True else: return False def exitShortCon2(self): if self.__macd[-1-self.__circ] is None: return False m1 = 0 for i in range(self.__circ): if self.__macd[-i-1] > self.__macd[-i-2]: m1 += 1 if m1 >= self.__circ: return True else: return False def sellCon1(self): if self.__macd[-1] >self.__range: return True else: return False def sellCon2(self): if self.__macd[-1-self.__circ] is None: return False m1 = 0 for i in range(self.__circ): if self.__macd[-i-1] < self.__macd[-i-2]: m1 += 1 if m1 >= self.__circ: return True else: return False def onBars(self, bars): # If a position was not opened, check if we should enter a long position. if self.__macd[-1]is None: return self.__range=self.__prices[0]*0.004 self.testCon() if self.__longPos is not None: if self.exitLongSignal(): self.__longPos.exitMarket() elif self.__shortPos is not None: if self.exitShortSignal(): self.__shortPos.exitMarket() elif self.__longPos is None and self.__shortPos is None: if self.enterLongSignal(): shares = int(self.getBroker().getEquity() * 0.2 / bars[self.__instrument].getPrice()) self.__longPos = self.enterLong(self.__instrument, shares) elif self.enterShortSignal(): shares = int(self.getBroker().getEquity() * 0.2 / bars[self.__instrument].getPrice()) self.__shortPos = self.enterShort(self.__instrument, shares) def enterLongSignal(self) : if self.buyCon1() and self.buyCon2(): return True else: return False def enterShortSignal(self) : if self.sellCon1() and self.sellCon2(): return True else: return False def exitLongSignal(self) : if self.exitLongCon1() and self.exitLongCon2() and not self.__longPos.exitActive(): return True else: return False def exitShortSignal(self): if self.exitShortCon1() and self.exitShortCon2() and not self.__shortPos.exitActive(): return True else: return False
def __init__(self, feed, instrument, bollingerlength, numStdDev, closelength, ccMAlength, malength, space): strategy.BacktestingStrategy.__init__(self, feed) self.getBroker().setFillStrategy(DefaultStrategy(None)) self.getBroker().setCommission(TradePercentage(0.002)) self.__instrument = instrument self.__bollingerlength = int(bollingerlength) numStdDev = float(numStdDev) / 10 self.__closelength = int(closelength) self.__ccMAlength = int(ccMAlength) self.__malength = int(malength) self.__longPos = None self.__shortPos = None self.__close = feed[instrument].getCloseDataSeries() self.__high = feed[instrument].getHighDataSeries() self.__low = feed[instrument].getLowDataSeries() self.__datetime = feed[instrument].getDateTimes() self.__bollinger = bollinger.BollingerBands(self.__close, self.__bollingerlength, int(numStdDev)) self.__UpperBand = self.__bollinger.getUpperBand() self.__LowerBand = self.__bollinger.getLowerBand() self.__MA = SequenceDataSeries() self.__space = int(space) self.__enter = 0 self.__enterLong1 = 0 self.__enterLong2 = 0 self.__enterShort1 = 0 self.__enterShort2 = 0 self.__exitLong1 = 0 self.__exitLong2 = 0 self.__exitShort1 = 0 self.__exitShort1 = 0 #for test ######################################################################### self.__p = SequenceDataSeries() self.__filterCon = SequenceDataSeries() self.__ccMACon1 = SequenceDataSeries() self.__ccMACon2 = SequenceDataSeries() self.__enterCon = SequenceDataSeries() self.__enterLongCon1 = SequenceDataSeries() self.__enterLongCon2 = SequenceDataSeries() self.__enterShortCon1 = SequenceDataSeries() self.__enterShortCon2 = SequenceDataSeries() self.__exitLongCon1 = SequenceDataSeries() self.__exitLongCon2 = SequenceDataSeries() self.__exitShortCon1 = SequenceDataSeries() self.__exitShortCon2 = SequenceDataSeries()
class Bollinger_Bandit(strategy.BacktestingStrategy): def __init__(self, feed, instrument, bollingerlength, numStdDev, closelength, ccMAlength, malength, space): strategy.BacktestingStrategy.__init__(self, feed) self.getBroker().setFillStrategy(DefaultStrategy(None)) self.getBroker().setCommission(TradePercentage(0.002)) self.__instrument = instrument self.__bollingerlength = int(bollingerlength) numStdDev = float(numStdDev) / 10 self.__closelength = int(closelength) self.__ccMAlength = int(ccMAlength) self.__malength = int(malength) self.__longPos = None self.__shortPos = None self.__close = feed[instrument].getCloseDataSeries() self.__high = feed[instrument].getHighDataSeries() self.__low = feed[instrument].getLowDataSeries() self.__datetime = feed[instrument].getDateTimes() self.__bollinger = bollinger.BollingerBands(self.__close, self.__bollingerlength, int(numStdDev)) self.__UpperBand = self.__bollinger.getUpperBand() self.__LowerBand = self.__bollinger.getLowerBand() self.__MA = SequenceDataSeries() self.__space = int(space) self.__enter = 0 self.__enterLong1 = 0 self.__enterLong2 = 0 self.__enterShort1 = 0 self.__enterShort2 = 0 self.__exitLong1 = 0 self.__exitLong2 = 0 self.__exitShort1 = 0 self.__exitShort1 = 0 #for test ######################################################################### self.__p = SequenceDataSeries() self.__filterCon = SequenceDataSeries() self.__ccMACon1 = SequenceDataSeries() self.__ccMACon2 = SequenceDataSeries() self.__enterCon = SequenceDataSeries() self.__enterLongCon1 = SequenceDataSeries() self.__enterLongCon2 = SequenceDataSeries() self.__enterShortCon1 = SequenceDataSeries() self.__enterShortCon2 = SequenceDataSeries() self.__exitLongCon1 = SequenceDataSeries() self.__exitLongCon2 = SequenceDataSeries() self.__exitShortCon1 = SequenceDataSeries() self.__exitShortCon2 = SequenceDataSeries() ########################################################################## def getHigh(self): return self.__high def getLow(self): return self.__low def getClose(self): return self.__close def getBollinger(self): return self.__UpperBand, self.__LowerBand def getMA(self): return self.__MA def getDateTime(self): return self.__datetime def getPosition(self): return self.__p def getTest(self): return self.__filterCon, self.__ccMACon1, self.__ccMACon2, \ self.__enterCon, self.__enterLongCon1, self.__enterLongCon2, self.__enterShortCon1, \ self.__enterShortCon2, self.__exitLongCon1, self.__exitLongCon2, \ self.__exitShortCon1, self.__exitShortCon2 def onEnterCanceled(self, position): if self.__longPos == position: self.__longPos = None elif self.__shortPos == position: self.__shortPos = None else: assert(False) def onExitOk(self, position): if self.__longPos == position: self.__longPos = None elif self.__shortPos == position: self.__shortPos = None else: assert(False) def onBars(self, bars): # If a position was not opened, check if we should enter a long position. bar = bars[self.__instrument] # filter datetime ################################################################################### filterCon = len(self.__close) < max(self.__bollingerlength, self.__malength, self.__closelength) self.__filterCon.append(filterCon) if filterCon: return # record position #################################################################################### if self.__longPos is not None and self.__shortPos is None: self.__p.append(1) elif self.__longPos is None and self.__shortPos is not None: self.__p.append(-1) else: self.__p.append(0) # calculate ccMA #################################################################################### ccMACon1 = self.__longPos is not None or self.__shortPos is not None ccMACon2 = self.__malength > self.__ccMAlength if ccMACon1 and ccMACon2: self.__malength = self.__malength - 1 elif not ccMACon1: self.__malength = 50 self.__ccMA = np.mean(self.__close[-self.__malength:]) # print self.__malength, self.__ccMA self.__MA.append(self.__ccMA) self.__ccMACon1.append(ccMACon1) self.__ccMACon2.append(ccMACon2) #open and close condition ###################################################################################### self.__enterLong1 = (cross.cross_above(self.__high, self.__UpperBand) > 0) self.__enterLong2 = (bar.getClose() >= max(self.__close[-self.__closelength:])) self.__enter = ((self.__UpperBand[-1] - self.__LowerBand[-1]) / bar.getClose() > float(self.__space) / 1000) # print (self.__UpperBand[-1] - self.__LowerBand[-1]) / bar.getClose() self.__enterShort1 = cross.cross_below(self.__low, self.__LowerBand) > 0 self.__enterShort2 = bar.getClose() <= min(self.__close[-self.__closelength:]) self.__exitLong1 = (bar.getClose() < self.__ccMA) self.__exitLong2 = (self.__ccMA < self.__UpperBand[-1]) self.__exitShort1 = (bar.getClose() > self.__ccMA) self.__exitShort2 = (self.__ccMA > self.__LowerBand[-1]) self.__enterCon.append(self.__enter) self.__enterLongCon1.append(self.__enterLong1) self.__enterLongCon2.append(self.__enterLong2) self.__enterShortCon1.append(self.__enterShort1) self.__enterShortCon2.append(self.__enterShort2) self.__exitLongCon1.append(self.__exitLong1) self.__exitLongCon2.append(self.__exitLong2) self.__exitShortCon1.append(self.__exitShort1) self.__exitShortCon2.append(self.__exitShort2) #open and close ####################################################################################### if self.__longPos is not None: if self.exitLongSignal(): self.__longPos.exitMarket() # if self.__shortPos is not None: # print 11 # self.info("intend long close") # print (self.__UpperBand[-1] - self.__LowerBand[-1]) / bar.getClose() elif self.__shortPos is not None: if self.exitShortSignal(): self.__shortPos.exitMarket() # self.info("intend short close") # print (self.__UpperBand[-1] - self.__LowerBand[-1]) / bar.getClose() else: if self.enterLongSignal(): shares = int(self.getBroker().getCash() * 0.2 / bars[self.__instrument].getPrice()) self.__longPos = self.enterLong(self.__instrument, shares) # self.info("intend long open") # print (self.__UpperBand[-1] - self.__LowerBand[-1]) / bar.getClose() elif self.enterShortSignal(): shares = int(self.getBroker().getCash() * 0.2 / bars[self.__instrument].getPrice()) self.__shortPos = self.enterShort(self.__instrument, shares) # self.info("intend short open") # print (self.__UpperBand[-1] - self.__LowerBand[-1]) / bar.getClose() def enterLongSignal(self): if self.__enterLong1 and self.__enterLong2 and self.__enter: return True def enterShortSignal(self): if self.__enterShort1 and self.__enterShort2 and self.__enter: return True def exitLongSignal(self): if self.__exitLong1 and self.__exitLong2 and not self.__longPos.exitActive(): return True def exitShortSignal(self): if self.__exitShort1 and self.__exitShort2 and not self.__shortPos.exitActive(): return True
class bollinger_band(strategy.BacktestingStrategy): def __init__(self, feed, instrument,longline,shortline,bollingerlength, numStdDev): strategy.BacktestingStrategy.__init__(self, feed) self.getBroker().setFillStrategy(DefaultStrategy(None)) self.getBroker().setCommission(TradePercentage(0.001)) self.__instrument = instrument self.__bollingerlength = int(bollingerlength) self.__close = feed[instrument].getMatchDataSeries() numStdDev = float(numStdDev) / 10 self.__longPos = [] self.__shortPos = [] self.__macd=macd.MACD(self.__close,shortline,longline,10) self.__bollinger = bollinger.BollingerBands(self.__macd, self.__bollingerlength, int(numStdDev)) self.__UpperBand = self.__bollinger.getUpperBand() self.__LowerBand = self.__bollinger.getLowerBand() self.__position = SequenceDataSeries() self.__circ=5 self.__lastLongPos=None self.__lastShortPos=None self.__barNum=0 self.__macdMin=[] self.__macdMax=[] def getPrice(self): return self.__prices def getMACD(self): return self.__macd def getBollingerBands(self): return self.__bollinger def testCon(self): # record position ####################################################################### if len(self.__longPos) > 0: self.__position.append(len(self.__longPos)) if len(self.__shortPos)>0 : #print(self.__shortPos.getShares()) self.__position.append(-len(self.__shortPos)) elif len(self.__longPos)==0 and len(self.__shortPos)==0: self.__position.append(0) #print(0) def getTest(self): return self.__position def onBars(self, bars): bar = bars[self.__instrument] lower = self.__bollinger.getLowerBand()[-1] upper = self.__bollinger.getUpperBand()[-1] self.__barNum=self.__barNum+1 # print(self.getActivePositions()) if self.__macd[-1] is None: #print (self.__macd[-1]) return if self.__macd[-1]>self.__macdMax: self.__macdMax=self.__macd[-1] if self.__macd[-1]<=self.__macdMin: self.__macdMin=self.__macd[-1] if lower is None or upper is None: return self.testCon() if len(self.__longPos)> 0: if self.exitLongSignal(): for pos in self.__longPos: pos.exitMarket() elif len(self.__shortPos)>0: if self.exitShortSignal(): for pos in self.__shortPos: pos.exitMarket() if self.enterLongSignal(): for i in range(self.enterLongSignal()): shares = int(self.getBroker().getEquity() * 0.2 / bars[self.__instrument].getMatch()) # self.__longPos. self.__longPos.append(self.enterLong(self.__instrument, shares)) self.__lastLongPos=self.__barNum #print('long'+str(shares)) elif self.enterShortSignal(): for i in range(self.enterShortSignal()): shares = int(self.getBroker().getEquity() * 0.2 / bars[self.__instrument].getMatch()) self.__shortPos.append(self.enterShort(self.__instrument, shares)) self.__lastShortPos=self.__barNum #print('short'+str(shares)) def enterLongSignal (self) : if self.__lastLongPos is not None: if self.__barNum-self.__lastLongPos<60: return 0 if self.__UpperBand[-1-self.__circ] is None: return 0 m1 = 0 for i in range(self.__circ): if self.__macd[-i-1] <= self.__LowerBand[-i-2]: m1 += 1 if m1 >= self.__circ-1 and cross.cross_above(self.__macd,self.__LowerBand)>0: if self.__macd[-1]>0: return 0 else: if self.__macdMin==self.__macd[-1] : return 2 else: return 1 else: return 0 def enterShortSignal(self) : if self.__lastShortPos is not None: if self.__barNum-self.__lastShortPos<60: return 0 if self.__UpperBand[-1-self.__circ] is None: return 0 m1 = 0 for i in range(self.__circ): if self.__macd[-i-1] >= self.__UpperBand[-i-2]: m1 += 1 if m1 >= self.__circ-1 and cross.cross_below(self.__macd,self.__UpperBand)>0: if self.__macd[-1]<0: return 0 else: if self.__macdMax==self.__macd[-1]: return 2 else: return 1 else: return 0 def exitLongSignal(self) : if self.__UpperBand[-1-self.__circ] is None: return False m1 = 0 for i in range(self.__circ): if self.__macd[-i-1] >= self.__UpperBand[-i-2]: m1 += 1 if m1 >= self.__circ-1 and cross.cross_below(self.__macd,self.__UpperBand)>0: return True elif self.__macd[-1]>=self.__UpperBand[-1] and self.__macdMax==self.__macd[-1]: return True elif self.__macd[-1]*1.001>=self.__UpperBand[-1] and self.__macd[-1]>-0.1: return True else: return False def exitShortSignal(self): if self.__UpperBand[-1-self.__circ] is None: return False m1 = 0 for i in range(self.__circ): if self.__macd[-i-1] <= self.__LowerBand[-i-2]: m1 += 1 if m1 >= self.__circ-1 and cross.cross_above(self.__macd,self.__LowerBand)>0: return True elif self.__macd[-1]<=self.__LowerBand[-1] and self.__macdMin==self.__macd[-1]: return True elif self.__macd[-1]<=self.__LowerBand[-1]*1.001 and self.__macd[-1]<0.11: return True else: return False def onEnterCanceled(self, position): if self.__longPos[-1] == position: del self.__longPos[-1] self.__lastLongPos==None elif self.__shortPos[-1] == position: del self.__shortPos[-1] self.__lastShortPos==None else: assert(False) def onEnterOK(self,position): pass def onExitOk(self, position): if isinstance(position,LongPosition): self.__longPos = [] elif isinstance(position,ShortPosition): self.__shortPos = [] else: assert(False) def onExitCanceled(self, position): position.exitMarket()
class fourSMA(strategy.BacktestingStrategy): def __init__(self, feed, instrument, mall, mals, masl, mass): strategy.BacktestingStrategy.__init__(self, feed) self.getBroker().setFillStrategy(DefaultStrategy(None)) self.getBroker().setCommission(TradePercentage(0.001)) self.__instrument = instrument self.__close = feed[instrument].getCloseDataSeries() self.__longPos = None self.__shortPos = None self.__mall = ma.SMA(self.__close, int(mall)) self.__mals = ma.SMA(self.__close, int(mals)) self.__masl = ma.SMA(self.__close, int(masl)) self.__mass = ma.SMA(self.__close, int(mass)) self.__position = SequenceDataSeries() def getPrice(self): return self.__prices def getSMA(self): return self.__mall, self.__mals, self.__mass, self.__masl def testCon(self): # record position ####################################################################### if self.__longPos is not None: self.__position.append(1) if self.__shortPos is not None: self.__position.append(-1) elif self.__longPos is None and self.__shortPos is None: self.__position.append(0) def getTest(self): return self.__position def onEnterCanceled(self, position): if self.__longPos == position: self.__longPos = None elif self.__shortPos == position: self.__shortPos = None else: assert (False) def onExitOk(self, position): if self.__longPos == position: self.__longPos = None elif self.__shortPos == position: self.__shortPos = None else: assert (False) def onExitCanceled(self, position): position.exitMarket() def onEnterOk(self, position): pass def onBars(self, bars): bar = bars[self.__instrument] if self.__mall[-1] is None: return self.testCon() if self.__longPos is not None: if self.exitLongSignal(): self.__longPos.exitMarket() elif self.__shortPos is not None: if self.exitShortSignal(): self.__shortPos.exitMarket() elif self.__longPos is None and self.__shortPos is None: if self.enterLongSignal(): shares = int(self.getBroker().getEquity() * 0.2 / bar.getPrice()) self.__longPos = self.enterLong(self.__instrument, shares) elif self.enterShortSignal(): shares = int(self.getBroker().getEquity() * 0.2 / bar.getPrice()) self.__shortPos = self.enterShort(self.__instrument, shares) def enterLongSignal(self): if cross.cross_above(self.__mals, self.__mall) > 0: return True def enterShortSignal(self): if cross.cross_below(self.__mals, self.__mall) > 0: return True def exitLongSignal(self): if cross.cross_below( self.__mass, self.__masl) > 0 and not self.__longPos.exitActive(): return True def exitShortSignal(self): if cross.cross_above( self.__mass, self.__masl) > 0 and not self.__shortPos.exitActive(): return True
class fourSMA(strategy.BacktestingStrategy): def __init__(self, feed, instrument, mall, mals, masl, mass): strategy.BacktestingStrategy.__init__(self, feed) self.getBroker().setFillStrategy(DefaultStrategy(None)) self.getBroker().setCommission(TradePercentage(0.001)) self.__instrument = instrument self.__close = feed[instrument].getCloseDataSeries() self.__longPos = None self.__shortPos = None self.__mall = ma.SMA(self.__close, int(mall)) self.__mals = ma.SMA(self.__close, int(mals)) self.__masl = ma.SMA(self.__close, int(masl)) self.__mass = ma.SMA(self.__close, int(mass)) self.__position = SequenceDataSeries() def getPrice(self): return self.__prices def getSMA(self): return self.__mall,self.__mals,self.__mass,self.__masl def testCon(self): # record position ####################################################################### if self.__longPos is not None: self.__position.append(1) if self.__shortPos is not None: self.__position.append(-1) elif self.__longPos is None and self.__shortPos is None: self.__position.append(0) def getTest(self): return self.__position def onEnterCanceled(self, position): if self.__longPos == position: self.__longPos = None elif self.__shortPos == position: self.__shortPos = None else: assert(False) def onExitOk(self, position): if self.__longPos == position: self.__longPos = None elif self.__shortPos == position: self.__shortPos = None else: assert(False) def onExitCanceled(self, position): position.exitMarket() def onEnterOk(self, position): pass def onBars(self, bars): bar = bars[self.__instrument] if self.__mall[-1] is None: return self.testCon() if self.__longPos is not None: if self.exitLongSignal(): self.__longPos.exitMarket() elif self.__shortPos is not None: if self.exitShortSignal(): self.__shortPos.exitMarket() elif self.__longPos is None and self.__shortPos is None: if self.enterLongSignal(): shares = int(self.getBroker().getEquity() * 0.2 / bar.getPrice()) self.__longPos = self.enterLong(self.__instrument, shares) elif self.enterShortSignal(): shares = int(self.getBroker().getEquity() * 0.2 / bar.getPrice()) self.__shortPos = self.enterShort(self.__instrument, shares) def enterLongSignal(self) : if cross.cross_above(self.__mals, self.__mall) > 0: return True def enterShortSignal(self) : if cross.cross_below(self.__mals, self.__mall) > 0: return True def exitLongSignal(self) : if cross.cross_below(self.__mass, self.__masl) > 0 and not self.__longPos.exitActive(): return True def exitShortSignal(self): if cross.cross_above(self.__mass, self.__masl) > 0 and not self.__shortPos.exitActive(): return True
class midBaseStrategy(strategy.BacktestingStrategy): def getFeeds(self,timeFrom=None,timeTo=None): import os,sys xpower = os.path.abspath(os.path.join(os.path.dirname(__file__),os.pardir,os.pardir,os.pardir,'midProjects','histdata')) sys.path.append(xpower) import dataCenter as dataCenter self.dataCenter = dataCenter.dataCenter() feeds = self.dataCenter.getFeedsForPAT(dataProvider = self.dataProvider,storageType = self.storageType,instruments = self.instruments, period=self.period,timeTo = timeTo,timeFrom=timeFrom) return feeds def getFeedNew(self,timeFrom=None,timeTo=None): '''mid should not be named the same with base class''' import os,sys xpower = os.path.abspath(os.path.join(os.path.dirname(__file__),os.pardir,os.pardir,os.pardir,'midProjects','histdata')) sys.path.append(xpower) import dataCenter as dataCenter self.dataCenter = dataCenter.dataCenter() feed = self.dataCenter.getFeedForPAT(dataProvider = self.dataProvider,storageType = self.storageType,instruments = self.instruments, period=self.period,timeTo = timeTo,timeFrom=timeFrom) return feed def initEa(self,timeFrom=None,timeTo=None): self.results = {} feed = self.getFeedNew(timeFrom = timeFrom,timeTo = timeTo) self.mid_DEFAULT_MAX_LEN = 10 * DEFAULT_MAX_LEN mid_DEFAULT_MAX_LEN = self.mid_DEFAULT_MAX_LEN #mid set init cash cash_or_brk = 1000000 volumeLimit = 0.5 #mid used to calculate available volume for an order: availableVolume = volumeLeft * volumeLimit #mid set fillstrategy fillStrategy = fillstrategy.DefaultStrategy(volumeLimit = volumeLimit) broker = backtesting.Broker(cash_or_brk, feed) broker.setFillStrategy(fillStrategy) #mid init base strategy.BacktestingStrategy.__init__(self, feed,broker) #mid 计算ma将使用当天的收盘价格计算 #mid 1) self.closePrices = {} self.longPosition = {} self.shortPosition = {} self.buySignal = {} self.sellSignal = {} self.timeFrom = timeFrom self.timeTo = timeTo #mid follow vars will be used only this class self.__portfolio_value = SequenceDataSeries(maxLen = mid_DEFAULT_MAX_LEN) self.__available_cash = SequenceDataSeries(maxLen = mid_DEFAULT_MAX_LEN) self.__exitBar_position_pnl = {} self.__curLongPositionCost = {} #mid init position value self.__curShortPositionCost = {} #mid init position value self.__position_volume = {} #mid 当前持有头寸数量 self.__position_cost = {} #mid 当前持有头寸开仓成本 self.__position_pnl = {} #mid 当前持有头寸价值 self.__position_cumulativePNL = {} #mid 当前 symbol 持有头寸cumulative pnl 价值 self.__buy = {} self.__sell = {} for instrument in self.instruments: dataSeries = feed[instrument] dataSeries.setMaxLen(mid_DEFAULT_MAX_LEN) closeSeries = dataSeries.getCloseDataSeries() #mid 2) prices = closeSeries prices.setMaxLen(mid_DEFAULT_MAX_LEN) #mid follow vars will be used in subclass self.closePrices[instrument] = prices self.longPosition[instrument] = None self.shortPosition[instrument] = None self.buySignal[instrument] = False self.sellSignal[instrument] = False #mid follow vars will be used only this class self.__curLongPositionCost[instrument] = 0 #mid init position value self.__curShortPositionCost[instrument] = 0 self.__exitBar_position_pnl[instrument] = None #mid init position value self.__position_volume[instrument] = SequenceDataSeries(maxLen = mid_DEFAULT_MAX_LEN) #mid 当前持有头寸数量 self.__position_cost[instrument] = SequenceDataSeries(maxLen = mid_DEFAULT_MAX_LEN) #mid 当前持有头寸开仓成本 self.__position_pnl[instrument] = SequenceDataSeries(maxLen = mid_DEFAULT_MAX_LEN) #mid 当前持有头寸价值 self.__position_cumulativePNL[instrument] = SequenceDataSeries(maxLen = mid_DEFAULT_MAX_LEN) self.__buy[instrument] = SequenceDataSeries(maxLen = mid_DEFAULT_MAX_LEN) self.__sell[instrument] = SequenceDataSeries(maxLen = mid_DEFAULT_MAX_LEN) def getAssetStructure(self): #mid -------------------------------- #mid 当前账户资产结构如下方式获取 #mid Long 和 Short不会同时存在 #mid 在开仓前,若有反向持仓,则此过程查询并输出已持有的反向持仓 broker = self.getBroker() portfolio_value = broker.getEquity() cash = broker.getCash() if self.shortPosition is not None or self.longPosition is not None: bars = self.getFeed().getCurrentBars() positions = broker.getPositions() positionsOpenValue = {} positionsCloseValue = {} for key,value in positions.items(): print "key:"+key+",value:"+str(value) bar = bars.getBar(key) openPrice = bar.getOpen() closePrice = bar.getClose() share = broker.getShares(key) positionsOpenValue[key] = openPrice*share positionsCloseValue[key] = closePrice*share print print 'current bar asset structure' print 'open cash %2.f.' % (cash) for key,value in positionsOpenValue.items(): print "key:"+key+",value:"+str(value) print 'close cash %2.f.' % (cash) for key,value in positionsCloseValue.items(): print "key:"+key+",value:"+str(value) print 'portfolio:%2.f' % (portfolio_value) return portfolio_value,cash,sum(positionsCloseValue.values()) return portfolio_value,cash,0 def sampleSub01(self,instrument): """mid not called anywhere because of open price gap,method below is not right. """ broker = self.getBroker() a = broker.getEquity() b = self.getResult() lastOpenPrice = None lastClosePrice = None bar = self.getFeed().getLastBar(instrument) if bar is not None: lastOpenPrice = bar.getOpen() lastClosePrice = bar.getClose() #lastPrice = self.getLastPrice(instrument) pnl = (lastClosePrice - lastOpenPrice) * share else: pnl = 0 #mid instrument is dislisted. if(len(self.__position_cumulativePNL[instrument])>0): lastCumulativePNL = self.__position_cumulativePNL[instrument][-1] else: lastCumulativePNL = 0 def recordAccount(self): # record position ####################################################################### broker = self.getBroker() curTime = self.getCurrentDateTime() currentTime = self.getCurrentDateTime() cash = broker.getCash(includeShort=False) portfolio_value = broker.getEquity() #mid 按close价格计算的权益 print self.info("onBars().recordAccount().Current time:%s"%(str(currentTime))) self.info("onBars().recordAccount().----portfolio value: %.2f" % (portfolio_value)) self.info("onBars().recordAccount().----cash in portfolio: %.2f" % (cash)) self.__portfolio_value.appendWithDateTime(currentTime,portfolio_value) self.__available_cash.appendWithDateTime(currentTime,cash) totalCumulativePNL = 0 time = self.getCurrentDateTime() if(time == dt.datetime(2010,12,21,0,0)): a = 8 for instrument in self.instruments: share = broker.getShares(instrument) #mid position is dict of share lastClosePrice = self.getLastPrice(instrument) if(lastClosePrice is None): continue position_value = lastClosePrice*share if(share > 0): position_cost = self.__curLongPositionCost[instrument] elif(share < 0): position_cost = self.__curShortPositionCost[instrument] else: position_cost = 0 position_pnl = (position_value - position_cost) self.__position_volume[instrument].appendWithDateTime(currentTime,abs(share)) self.__position_cost[instrument].appendWithDateTime(currentTime,abs(position_cost)) self.__position_pnl[instrument].appendWithDateTime(currentTime,position_pnl) self.__buy[instrument].appendWithDateTime(currentTime,self.buySignal[instrument]) self.__sell[instrument].appendWithDateTime(currentTime,self.sellSignal[instrument]) if(share != 0): if(len(self.__position_pnl[instrument])>2): currentPositionPnl = self.__position_pnl[instrument][-1] lastPositionPnl = self.__position_pnl[instrument][-2] currentBarPnl = currentPositionPnl - lastPositionPnl else: currentBarPnl = self.__position_pnl[instrument][-1] else: currentBarPnl = 0 if(self.__exitBar_position_pnl[instrument] is not None): """mid 如果当前bar有某个position在open price被closed掉,则当前bar的position_pnl是0. 在当前bar的openprice和上一bar的closeprice之间没有gap时,这个算法是合理的,但是,gap往往是存在的, 所以,据此计算的barPnl在exitbar上会有gap导致的误差 在此特别处理exitbar """ currentExitedPositionPnl = self.__exitBar_position_pnl[instrument] lastPositionPnl = self.__position_pnl[instrument][-2] currentBarExitedPnl = currentExitedPositionPnl - lastPositionPnl self.__exitBar_position_pnl[instrument] = None currentBarPnl = currentBarPnl + currentBarExitedPnl if(len(self.__position_cumulativePNL[instrument])>0): lastCumulativePNL = self.__position_cumulativePNL[instrument][-1] cumulativePNL = lastCumulativePNL + currentBarPnl else: cumulativePNL = currentBarPnl self.__position_cumulativePNL[instrument].appendWithDateTime(currentTime,cumulativePNL) if(True): self.info("onBars().recordAccount().--------mid current bar PNL: %.3f" %(currentBarPnl)) self.info("onBars().recordAccount().--------%s" % (instrument)) self.info("onBars().recordAccount().--------share:%.3f" % (share)) self.info("onBars().recordAccount().--------lastClosePrice:%.3f" % (lastClosePrice)) self.info("onBars().recordAccount().--------mid calculated position value: %.3f" %(position_value)) self.info("onBars().recordAccount().--------mid position cost: %.3f" %(position_cost)) self.info("onBars().recordAccount().--------mid calculated postion pnl: %.3f" %(position_pnl)) self.info("onBars().recordAccount().--------mid CumulativePNL: %.3f" %(cumulativePNL)) totalCumulativePNL = totalCumulativePNL + cumulativePNL if(abs(1000000 - (portfolio_value - totalCumulativePNL))>0.00000001): self.info("onBars().recordAccount().--------mid initCash: %.3f" %(portfolio_value - totalCumulativePNL)) a = 8 def getPortfolioValue(self): return self.__portfolio_value def getAvailableCash(self): return self.__available_cash def getCurInstrument(self): return self.curInstrument def getPositionValue(self,instrument): return self.__position_cumulativePNL[instrument] def getPositionVolume(self,instrument): return self.__position_volume[instrument] def getPositionCost(self,instrument): return self.__position_cost[instrument] def getPositionPnl(self,instrument): return self.__position_pnl[instrument] def getBuy(self,instrument): return self.__buy[instrument] def getSell(self,instrument): return self.__sell[instrument] def onEnterOk(self, position): '''mid 由于getEquity()返回的是依据当日close价格计算出来的权益 所以,这个值不能作为持仓成本 持仓成本需要以onEnterOk时bar的open价格计算 由于经常有跳开现象,所以依据bar(n-1).close发出的market order, 在bar(n).open执行时通常会有gap出现,表现在position_cost图上时就是持有成本离计划成本会有跳口, ''' print currentTime = self.getCurrentDateTime() execInfo = position.getEntryOrder().getExecutionInfo() self.info("onEnterOK().ExecutionInfo.Current time: %s"%(execInfo.getDateTime())) #mid 1)record the position cost instrument = position.getInstrument() feed = self.getFeed() bars = feed.getCurrentBars() bar = bars.getBar(instrument) openPrice = bar.getOpen() closePrice = self.getLastPrice(instrument) #mid lastPrice == closePrice if(False): '''mid long+short 计算获取instrument的净头寸 long = 10,short = -5 则position = 5 ''' share = self.getBroker().getShares(instrument) else: '''mid only long or short 计算当前position代表的头寸 如果当前为long,则求出long头寸并不考虑short long = 10,short = -5 若position == long 则此处求出 position=10 ''' share = position.getShares() if isinstance(position, strategy.position.LongPosition): self.__curLongPositionCost[instrument] = openPrice*share if isinstance(position, strategy.position.ShortPosition): self.__curShortPositionCost[instrument] = openPrice*share #mid 1.1) a example to show price gap planedCost = 100000 if(planedCost - abs(self.__curLongPositionCost[instrument]) > 1000): '''mid 跳开gap导致的n-1 day计划持仓金额和n day实际持仓金额之间的差额 以n-1day的close价格为依据计算share to open n-1 day close = 10 n day open = 9.8 如果是要open 100000元 则原计划持有数量shares = 100000/10 = 10000 实际持有成本 = 计划持有数量 × 实际open价格 = 10000 × 9.8 = 980000''' pass #mid 2)log account info after enterOKed. execInfo = position.getEntryOrder().getExecutionInfo() portfolio = self.getResult() cash = self.getBroker().getCash() self.info("onEnterOk().symbol:%s" % (instrument)) self.info("onEnterOk().current available cash: %.2f,portfolio: %.2f." % (cash,portfolio)) if isinstance(position, strategy.position.LongPosition): print str(self.__curLongPositionCost[instrument])+'='+str(share)+'*'+str(openPrice) self.info("onEnterOK().ExecutionInfo: %s,OPEN LONG %.2f at $%.2f" % (execInfo.getDateTime(),execInfo.getQuantity(),execInfo.getPrice())) elif isinstance(position, strategy.position.ShortPosition): print str(self.__curShortPositionCost[instrument])+'='+str(share)+'*'+str(openPrice) self.info("onEnterOK().ExecutionInfo: %s,OPEN SHORT %.2f at $%.2f" % (execInfo.getDateTime(),execInfo.getQuantity(),execInfo.getPrice())) def onEnterCanceled(self, position): instrument = position.getInstrument() self.info("onEnterCanceled().current available cash: %.2f." % (self.getBroker().getCash())) if isinstance(position, strategy.position.LongPosition): self.longPosition[instrument] = None self.info("onEnterCanceled().OPEN LONG cancled.") elif isinstance(position, strategy.position.ShortPosition): self.shortPosition[instrument] = None self.info("onEnterCanceled().OPEN SHORT cancled.") def onExitOk(self, position): execInfo = position.getExitOrder().getExecutionInfo() portfolio = self.getResult() cash = self.getBroker().getCash() instrument = position.getInstrument() print currentTime = self.getCurrentDateTime() self.info("onExitOk().ExecutionInfo.Current time: %s"%(execInfo.getDateTime())) self.info("onExitOk().instrument:%s." % (instrument)) self.info("onExitOk().current available cash: %.2f,portfolio: %.2f." % (cash,portfolio)) exQuantity = execInfo.getQuantity() exPrice = execInfo.getPrice() exAmount = exQuantity * exPrice #self.sampleSub01(instrument) if isinstance(position, strategy.position.LongPosition): positionCost = self.__curLongPositionCost[instrument] self.__exitBar_position_pnl[instrument] = exAmount - positionCost self.longPosition[instrument] = None self.__curLongPositionCost[instrument] = 0 self.info("onExitOk().ExecutionInfo: %s,CLOSE LONG %.2f at $%.2f" % (execInfo.getDateTime(),execInfo.getQuantity(),execInfo.getPrice())) elif isinstance(position, strategy.position.ShortPosition): positionCost = self.__curShortPositionCost[instrument] self.__exitBar_position_pnl[instrument] = -exAmount - positionCost self.shortPosition[instrument] = None self.__curShortPositionCost[instrument] = 0 self.info("onExitOk().ExecutionInfo: %s,CLOSE SHORT %.2f at $%.2f" % (execInfo.getDateTime(),execInfo.getQuantity(),execInfo.getPrice())) def onExitCanceled(self, position): # If the exit was canceled, re-submit it. if isinstance(position, strategy.position.LongPosition): self.longPosition[instrument] = None elif isinstance(position, strategy.position.ShortPosition): self.shortPosition[instrument] = None def logInfo(self,bars = None): pLong,pShort = 0,0 if(self.longPosition is not None): pLong = self.longPosition.getShares() if(self.shortPosition is not None): pShort = self.shortPosition.getShares() bar = bars[self.instrument] pOpen = bar.getOpen() pHigh = bar.getHigh() pLow = bar.getLow() pClose = bar.getClose() pPrice = bar.getPrice() self.info('logInfo().price:%.3f,open:%.2f,high:%.2f,low:%.2f,close:%.2f'%(pPrice,pOpen,pHigh,pLow,pClose)) #self.info('long:%.2f#short:%.2f'%(pLong,pShort)) def closePosition(self): for instrument in self.instruments: if(self.longPosition[instrument] is not None and self.sellSignal[instrument] == True and not self.longPosition[instrument].exitActive()): print self.info("onBars().closePosition(), instrument:%s" % (instrument)) self.info("onBars().closePosition(), LONG POSITION to close %.2f" % (self.longPosition[instrument].getShares())) self.longPosition[instrument].exitMarket() if(self.shortPosition[instrument] is not None and self.buySignal[instrument] == True and not self.shortPosition[instrument].exitActive()): print self.info("onBars().closePosition(), instrument:%s" % (instrument)) self.info("onBars().closePosition(), SHORT POSITION to close %.2f" % (self.shortPosition[instrument].getShares())) self.shortPosition[instrument].exitMarket() def openPosition(self): '''mid 此处是onBars,这个和zipline的概念完全不同 zipline中,需要覆写的是handle_data,这个东西是个tick概念,所以没有OHLC的,只是个price PAT中,每次onBars,都会传入一个newbar的OHLC,此时,要如何按这个OHLC决策,全由你 依据OHLC做完决策后,可以发送交易指令: * Order.Type.MARKET * Order.Type.LIMIT * Order.Type.STOP * Order.Type.STOP_LIMIT 1.市价单,依据下一个bar的openPrice执行命令: self.enterLong() 2.限价单 3.止损单市价单 4.止损限价单 当前似乎没有止盈单 在均线策略中,应该在每个newbar到来时,按closePrice的均线计算指标值,然后发送市价单 1.每个newbar按close价格计算指标,并在下一个bar按open成交 2.每个newbar按open价格计算指标,并在此newbar按open成交 以上1,2的计算逻辑是一致的。如果当前bar的close和下一个bar的open相差无几时,两种算法的回测结果也应相差无几 ''' # mid 2)open if(self.shortAllowed): for instrument in self.instruments: self.curInstrument = instrument if(self.sellSignal[instrument] == True): # Enter a buy market order. The order is good till canceled. bar = self.getFeed().getLastBar(instrument) volume = 0 lastClose = 0 if bar is not None: volume = bar.getVolume() lastClose = bar.getClose() shares = self.money.getShares(strat = self) print self.info("onBars().openPosition(), instrument %s" % (instrument)) self.info("onBars().openPosition(), SHORT POSITION to open %.2f" % (shares)) self.info("onBars().openPosition(), lastClose: %.2f,%.2f" % (self.getLastPrice(instrument),lastClose)) self.info("onBars().openPosition(), need amount: %.2f" % (shares*self.getLastPrice(instrument))) self.info("onBars().openPosition(), available amount: %.2f." % (self.getBroker().getCash() )) self.info("onBars().openPosition(), available volume: %.2f." % (volume)) self.shortPosition[instrument] = self.enterShort(instrument, shares, True) if(self.longAllowed): for instrument in self.instruments: self.curInstrument = instrument if(self.buySignal[instrument] == True): shares = self.money.getShares(strat = self) print self.info("onBars().openPosition(), instrument %s" % (instrument)) self.info("onBars().openPosition(), LONG POSITION to open %.2f" % (shares) ) self.info("onBars().openPosition(), need amount: %.2f." % (shares*self.getLastPrice(instrument))) self.info("onBars().openPosition(), available amount: %.2f." % (self.getBroker().getCash() )) self.longPosition[instrument] = self.enterLong(instrument, shares, True) def __analiseEachSymbol(self,instrument): dataForCandle = self.dataCenter.getCandleData(dataProvider = self.dataProvider,dataStorage = self.storageType,dataPeriod = self.period, symbol = instrument,dateStart=self.timeFrom,dateEnd = self.timeTo) self.analyzer.analyseEachSymbol(self.results[instrument],dataForCandle,InKLine = self.InKLine) def __analiseSummary(self): dataProvider = self.benchDataProvider instrument = self.benchSymbol dataForCandle = self.dataCenter.getCandleData(dataProvider = dataProvider,dataStorage = self.storageType,dataPeriod = self.period, symbol = instrument,dateStart=self.timeFrom,dateEnd = self.timeTo) self.analyzer.analyseSummary(self.result,dataForCandle) def run(self,timeFrom = None,timeTo = None): self.initEa(timeFrom = timeFrom,timeTo = timeTo) self.initIndicators() #self.strat.setUseAdjustedValues(False) self.initAnalyzer() strategy.BacktestingStrategy.run(self) for instrument in self.instruments: buy = self.getBuy(instrument) sell = self.getSell(instrument) position_value = self.getPositionValue(instrument) position_volume = self.getPositionVolume(instrument) position_cost = self.getPositionCost(instrument) position_pnl = self.getPositionPnl(instrument) self.results[instrument] = pd.DataFrame({'position_volume':list(position_volume),'position_cost':list(position_cost), 'position_pnl':list(position_pnl), 'buy':list(buy),'sell':list(sell),'position_value':list(position_value)}, columns=['position_volume','position_cost','position_pnl','buy','sell','position_value'], index=position_volume.getDateTimes()) self.addIndicators(instrument) #------------------------------------ if(self.toPlotEachSymbol): self.__analiseEachSymbol(instrument) if(self.toPlotSummary): portfolio_value = self.getPortfolioValue() available_cash = self.getAvailableCash() self.result = pd.DataFrame({'available_cash':list(available_cash),'portfolio_value':list(portfolio_value)}, columns=['available_cash','portfolio_value'], index=portfolio_value.getDateTimes()) self.__analiseSummary() return self.results #mid from ea #---------------------------------------------------------------------- def summary(self): return "from %s to %s:returns:%.2f%%,sharpe:%.2f,MaxDrawdown:%.2f%%,Longest drawdown duration:(%s)" % (str(self.timeFrom),str(self.timeTo), self.returnsAnalyzer.getCumulativeReturns()[-1] * 100, self.sharpeRatioAnalyzer.getSharpeRatio(0.05), self.drawdownAnalyzer.getMaxDrawDown() * 100, self.drawdownAnalyzer.getLongestDrawDownDuration()) def detail(self): """""" print "-------------------------------------------------------------------------" print "Final portfolio value: $%.2f" % self.getResult() print "Cumulative returns: %.2f %%" % (self.returnsAnalyzer.getCumulativeReturns()[-1] * 100) print "Sharpe ratio: %.2f" % (self.sharpeRatioAnalyzer.getSharpeRatio(0.05)) print "Max. drawdown: %.2f %%" % (self.drawdownAnalyzer.getMaxDrawDown() * 100) print "Longest drawdown duration: (%s)" % (self.drawdownAnalyzer.getLongestDrawDownDuration()) print print "Total trades: %d" % (self.tradesAnalyzer.getCount()) if self.tradesAnalyzer.getCount() > 0: profits = self.tradesAnalyzer.getAll() print "Avg. profit: $%2.f" % (profits.mean()) print "Profits std. dev.: $%2.f" % (profits.std()) print "Max. profit: $%2.f" % (profits.max()) print "Min. profit: $%2.f" % (profits.min()) returns = self.tradesAnalyzer.getAllReturns() print "Avg. return: %2.f %%" % (returns.mean() * 100) print "Returns std. dev.: %2.f %%" % (returns.std() * 100) print "Max. return: %2.f %%" % (returns.max() * 100) print "Min. return: %2.f %%" % (returns.min() * 100) print print "Profitable trades: %d" % (self.tradesAnalyzer.getProfitableCount()) if self.tradesAnalyzer.getProfitableCount() > 0: profits = self.tradesAnalyzer.getProfits() print "Avg. profit: $%2.f" % (profits.mean()) print "Profits std. dev.: $%2.f" % (profits.std()) print "Max. profit: $%2.f" % (profits.max()) print "Min. profit: $%2.f" % (profits.min()) returns = self.tradesAnalyzer.getPositiveReturns() print "Avg. return: %2.f %%" % (returns.mean() * 100) print "Returns std. dev.: %2.f %%" % (returns.std() * 100) print "Max. return: %2.f %%" % (returns.max() * 100) print "Min. return: %2.f %%" % (returns.min() * 100) print print "Unprofitable trades: %d" % (self.tradesAnalyzer.getUnprofitableCount()) if self.tradesAnalyzer.getUnprofitableCount() > 0: losses = self.tradesAnalyzer.getLosses() print "Avg. loss: $%2.f" % (losses.mean()) print "Losses std. dev.: $%2.f" % (losses.std()) print "Max. loss: $%2.f" % (losses.min()) print "Min. loss: $%2.f" % (losses.max()) returns = self.tradesAnalyzer.getNegativeReturns() print "Avg. return: %2.f %%" % (returns.mean() * 100) print "Returns std. dev.: %2.f %%" % (returns.std() * 100) print "Max. return: %2.f %%" % (returns.max() * 100) print "Min. return: %2.f %%" % (returns.min() * 100) print "-------------------------------------------------------------------------" def initAnalyzer(self): from pyalgotrade.stratanalyzer import sharpe from pyalgotrade.stratanalyzer import returns from pyalgotrade.stratanalyzer import drawdown from pyalgotrade.stratanalyzer import trades # 1.0) 策略结果 self.returnsAnalyzer = returns.Returns() # 1.1) 夏普比率 self.sharpeRatioAnalyzer = sharpe.SharpeRatio() # 1.2) self.drawdownAnalyzer = drawdown.DrawDown() # 1.3) self.tradesAnalyzer = trades.Trades() self.attachAnalyzer(self.sharpeRatioAnalyzer) self.attachAnalyzer(self.returnsAnalyzer) self.attachAnalyzer(self.tradesAnalyzer) self.attachAnalyzer(self.drawdownAnalyzer)
class midBaseStrategy(strategy.BacktestingStrategy): def getFeeds(self, timeFrom=None, timeTo=None): import os, sys xpower = os.path.abspath( os.path.join(os.path.dirname(__file__), os.pardir, os.pardir, os.pardir, 'midProjects', 'histdata')) sys.path.append(xpower) import dataCenter as dataCenter self.dataCenter = dataCenter.dataCenter() feeds = self.dataCenter.getFeedsForPAT(dataProvider=self.dataProvider, storageType=self.storageType, instruments=self.instruments, period=self.period, timeTo=timeTo, timeFrom=timeFrom) return feeds def initEa(self, timeFrom=None, timeTo=None): feeds = self.getFeeds(timeFrom=timeFrom, timeTo=timeTo) instrument = self.instrument strategy.BacktestingStrategy.__init__(self, feeds[instrument]) self.mid_DEFAULT_MAX_LEN = 10 * DEFAULT_MAX_LEN mid_DEFAULT_MAX_LEN = self.mid_DEFAULT_MAX_LEN #mid 计算ma将使用当天的收盘价格计算 #mid 1) feed = feeds[instrument] dataSeries = feed[instrument] dataSeries.setMaxLen(mid_DEFAULT_MAX_LEN) closeSeries = dataSeries.getCloseDataSeries() #mid 2) prices = closeSeries prices.setMaxLen(mid_DEFAULT_MAX_LEN) self.closePrices = prices #mid follow vars will be used in subclass self.timeFrom = timeFrom self.timeTo = timeTo self.instrument = instrument self.longPosition = None self.shortPosition = None self.buySignal = False self.sellSignal = False #mid follow vars will be used only this class self.__curPositionCost = 0 #mid init position value mid_DEFAULT_MAX_LEN = self.mid_DEFAULT_MAX_LEN self.__position_volume = SequenceDataSeries( maxLen=mid_DEFAULT_MAX_LEN) #mid 当前持有头寸数量 self.__position_cost = SequenceDataSeries( maxLen=mid_DEFAULT_MAX_LEN) #mid 当前持有头寸开仓成本 self.__position_pnl = SequenceDataSeries( maxLen=mid_DEFAULT_MAX_LEN) #mid 当前持有头寸价值 self.__portfolio_value = SequenceDataSeries(maxLen=mid_DEFAULT_MAX_LEN) self.__buy = SequenceDataSeries(maxLen=mid_DEFAULT_MAX_LEN) self.__sell = SequenceDataSeries(maxLen=mid_DEFAULT_MAX_LEN) def getAssetStructure(self): #mid -------------------------------- #mid 当前账户资产结构如下方式获取 #mid Long 和 Short不会同时存在 #mid 在开仓前,若有反向持仓,则此过程查询并输出已持有的反向持仓 broker = self.getBroker() portfolio_value = broker.getEquity() cash = broker.getCash() if self.shortPosition is not None or self.longPosition is not None: bars = self.getFeed().getCurrentBars() positions = broker.getPositions() positionsOpenValue = {} positionsCloseValue = {} for key, value in positions.items(): print "key:" + key + ",value:" + str(value) bar = bars.getBar(key) openPrice = bar.getOpen() closePrice = bar.getClose() share = broker.getShares(key) positionsOpenValue[key] = openPrice * share positionsCloseValue[key] = closePrice * share print print 'current bar asset structure' print 'open cash %2.f.' % (cash) for key, value in positionsOpenValue.items(): print "key:" + key + ",value:" + str(value) print 'close cash %2.f.' % (cash) for key, value in positionsCloseValue.items(): print "key:" + key + ",value:" + str(value) print 'portfolio:%2.f' % (portfolio_value) return portfolio_value, cash, sum(positionsCloseValue.values()) return portfolio_value, cash, 0 def recordPositions(self): # record position ####################################################################### broker = self.getBroker() position = broker.getPositions() #mid position is dict of share share = broker.getShares( self.instrument) #mid position is dict of share lastPrice = self.getLastPrice(self.instrument) portfolio_value = broker.getEquity() #mid 按close价格计算的权益 cash = broker.getCash() position_value = portfolio_value - cash position_pnl = position_value - self.__curPositionCost print print 'cash: %.2f' % (cash) print 'position value: %.2f' % (portfolio_value - cash) print 'mid calc: %.2f' % (lastPrice * share + cash) print 'broker returned: %.2f' % (portfolio_value) curTime = self.getCurrentDateTime() currentTime = self.getCurrentDateTime() self.__position_volume.appendWithDateTime(currentTime, abs(share)) self.__position_cost.appendWithDateTime(currentTime, abs(self.__curPositionCost)) self.__position_pnl.appendWithDateTime(currentTime, position_pnl) self.__portfolio_value.appendWithDateTime(currentTime, portfolio_value) self.__buy.appendWithDateTime(currentTime, self.buySignal) self.__sell.appendWithDateTime(currentTime, self.sellSignal) def getInstrument(self): return self.instrument def getPortfolio(self): return self.__portfolio_value def getPositionVolume(self): return self.__position_volume def getPositionCost(self): return self.__position_cost def getPositionPnl(self): return self.__position_pnl def getBuy(self): return self.__buy def getSell(self): return self.__sell def onEnterOk(self, position): execInfo = position.getEntryOrder().getExecutionInfo() portfolio = self.getResult() cash = self.getBroker().getCash() '''mid 以下两种方法都是为了计算持仓成本 由于getEquity()返回的是依据当日close价格计算出来的权益 所以,这个值不能作为持仓成本 持仓成本需要以onEnterOk时bar的open价格计算 所以应使用第二种算法 由于经常有跳开现象,所以依据bar(n-1).close发出的market order, 在bar(n).open执行时通常会有gap出现,表现在position_cost图上时就是持有成本离计划成本会有跳口, ''' if (False): #mid two methods to cacl cost. portfolio_value = self.getBroker().getEquity() self.__curPositionCost = portfolio_value - cash else: feed = self.getFeed() bars = feed.getCurrentBars() bar = bars.getBar(self.instrument) openPrice = bar.getOpen() closePrice = self.getLastPrice( self.instrument) #mid lastPrice == closePrice share = self.getBroker().getShares(self.instrument) self.__curPositionCost = openPrice * share self.info("onEnterOk().current available cash: %.2f,portfolio: %.2f." % (cash, portfolio)) if isinstance(position, strategy.position.LongPosition): self.info("onEnterOK().ExecutionInfo: %s,OPEN LONG %.2f at $%.2f" % (execInfo.getDateTime(), execInfo.getQuantity(), execInfo.getPrice())) elif isinstance(position, strategy.position.ShortPosition): self.info( "onEnterOK().ExecutionInfo: %s,OPEN SHORT %.2f at $%.2f" % (execInfo.getDateTime(), execInfo.getQuantity(), execInfo.getPrice())) def onEnterCanceled(self, position): self.info("onEnterCanceled().current available cash: %.2f." % (self.getBroker().getCash())) if isinstance(position, strategy.position.LongPosition): self.longPosition = None self.info("onEnterCanceled().OPEN LONG cancled.") elif isinstance(position, strategy.position.ShortPosition): self.shortPosition = None self.info("onEnterCanceled().OPEN SHORT cancled.") def onExitOk(self, position): execInfo = position.getExitOrder().getExecutionInfo() portfolio = self.getResult() cash = self.getBroker().getCash() self.info("onExitOk().current available cash: %.2f,portfolio: %.2f." % (cash, portfolio)) if isinstance(position, strategy.position.LongPosition): self.longPosition = None self.info("onExitOk().ExecutionInfo: %s,CLOSE LONG %.2f at $%.2f" % (execInfo.getDateTime(), execInfo.getQuantity(), execInfo.getPrice())) elif isinstance(position, strategy.position.ShortPosition): self.shortPosition = None self.info( "onExitOk().ExecutionInfo: %s,CLOSE SHORT %.2f at $%.2f" % (execInfo.getDateTime(), execInfo.getQuantity(), execInfo.getPrice())) def onExitCanceled(self, position): # If the exit was canceled, re-submit it. if isinstance(position, strategy.position.LongPosition): self.longPosition = None elif isinstance(position, strategy.position.ShortPosition): self.shortPosition = None def logInfo(self, bars=None): pLong, pShort = 0, 0 if (self.longPosition is not None): pLong = self.longPosition.getShares() if (self.shortPosition is not None): pShort = self.shortPosition.getShares() bar = bars[self.instrument] pOpen = bar.getOpen() pHigh = bar.getHigh() pLow = bar.getLow() pClose = bar.getClose() pPrice = bar.getPrice() self.info( 'logInfo().price:%.3f,open:%.2f,high:%.2f,low:%.2f,close:%.2f' % (pPrice, pOpen, pHigh, pLow, pClose)) #self.info('long:%.2f#short:%.2f'%(pLong,pShort)) def closePosition(self): if (self.longPosition is not None and self.sellSignal == True): self.info( "onBars().Status info,before exitMarket(), LONG POSITION to close %.2f" % (self.longPosition.getShares())) self.longPosition.exitMarket() if (self.shortPosition is not None and self.buySignal == True): self.info( "onBars().Status info,before exitMarket(), SHORT POSITION to close %.2f" % (self.shortPosition.getShares())) self.shortPosition.exitMarket() def openPosition(self): '''mid 此处是onBars,这个和zipline的概念完全不同 zipline中,需要覆写的是handle_data,这个东西是个tick概念,所以没有OHLC的,只是个price PAT中,每次onBars,都会传入一个newbar的OHLC,此时,要如何按这个OHLC决策,全由你 依据OHLC做完决策后,可以发送交易指令: * Order.Type.MARKET * Order.Type.LIMIT * Order.Type.STOP * Order.Type.STOP_LIMIT 1.市价单,依据下一个bar的openPrice执行命令: self.enterLong() 2.限价单 3.止损单市价单 4.止损限价单 当前似乎没有止盈单 在均线策略中,应该在每个newbar到来时,按closePrice的均线计算指标值,然后发送市价单 1.每个newbar按close价格计算指标,并在下一个bar按open成交 2.每个newbar按open价格计算指标,并在此newbar按open成交 以上1,2的计算逻辑是一致的。如果当前bar的close和下一个bar的open相差无几时,两种算法的回测结果也应相差无几 ''' # mid 2)open if (self.buySignal == True): shares = self.money.getShares(strat=self) self.info( "onBars().Status info,before enterLong(), LONG POSITION to open %.2f,need amount: %.2f,available amount: %.2f." % (shares, shares * self.getLastPrice(self.instrument), self.getBroker().getCash())) self.longPosition = self.enterLong(self.instrument, shares, True) if (self.sellSignal == True): # Enter a buy market order. The order is good till canceled. shares = self.money.getShares(strat=self) self.info( "onBars().Status info,before enterShort(), SHORT POSITION to open %.2f,need amount: %.2f,available amount: %.2f." % (shares, shares * self.getLastPrice(self.instrument), self.getBroker().getCash())) self.shortPosition = self.enterShort(self.instrument, shares, True) def __analise(self): dataForCandle = self.dataCenter.getCandleData( dataProvider=self.dataProvider, dataStorage=self.storageType, dataPeriod=self.period, symbol=self.instrument, dateStart=self.timeFrom, dateEnd=self.timeTo) self.analyzer.analyze(self.result, dataForCandle, InKLine=self.InKLine) def run(self, timeFrom=None, timeTo=None): self.initEa(timeFrom=timeFrom, timeTo=timeTo) self.initIndicators() #self.strat.setUseAdjustedValues(False) self.initAnalyzer() strategy.BacktestingStrategy.run(self) buy = self.getBuy() sell = self.getSell() portfolio_value = self.getPortfolio() position_volume = self.getPositionVolume() position_cost = self.getPositionCost() position_pnl = self.getPositionPnl() self.result = pd.DataFrame( { 'position_volume': list(position_volume), 'position_cost': list(position_cost), 'position_pnl': list(position_pnl), 'buy': list(buy), 'sell': list(sell), 'portfolio_value': list(portfolio_value) }, columns=[ 'position_volume', 'position_cost', 'position_pnl', 'buy', 'sell', 'portfolio_value' ], index=position_volume.getDateTimes()) self.addIndicators() #------------------------------------ if (self.toPlot): self.__analise() return self.result #mid from ea #---------------------------------------------------------------------- def summary(self): return "from %s to %s:returns:%.2f%%,sharpe:%.2f,MaxDrawdown:%.2f%%,Longest drawdown duration:(%s)" % ( str(self.timeFrom), str(self.timeTo), self.returnsAnalyzer.getCumulativeReturns()[-1] * 100, self.sharpeRatioAnalyzer.getSharpeRatio(0.05), self.drawdownAnalyzer.getMaxDrawDown() * 100, self.drawdownAnalyzer.getLongestDrawDownDuration()) def detail(self): """""" print "-------------------------------------------------------------------------" print "Final portfolio value: $%.2f" % self.getResult() print "Cumulative returns: %.2f %%" % ( self.returnsAnalyzer.getCumulativeReturns()[-1] * 100) print "Sharpe ratio: %.2f" % ( self.sharpeRatioAnalyzer.getSharpeRatio(0.05)) print "Max. drawdown: %.2f %%" % ( self.drawdownAnalyzer.getMaxDrawDown() * 100) print "Longest drawdown duration: (%s)" % ( self.drawdownAnalyzer.getLongestDrawDownDuration()) print print "Total trades: %d" % (self.tradesAnalyzer.getCount()) if self.tradesAnalyzer.getCount() > 0: profits = self.tradesAnalyzer.getAll() print "Avg. profit: $%2.f" % (profits.mean()) print "Profits std. dev.: $%2.f" % (profits.std()) print "Max. profit: $%2.f" % (profits.max()) print "Min. profit: $%2.f" % (profits.min()) returns = self.tradesAnalyzer.getAllReturns() print "Avg. return: %2.f %%" % (returns.mean() * 100) print "Returns std. dev.: %2.f %%" % (returns.std() * 100) print "Max. return: %2.f %%" % (returns.max() * 100) print "Min. return: %2.f %%" % (returns.min() * 100) print print "Profitable trades: %d" % ( self.tradesAnalyzer.getProfitableCount()) if self.tradesAnalyzer.getProfitableCount() > 0: profits = self.tradesAnalyzer.getProfits() print "Avg. profit: $%2.f" % (profits.mean()) print "Profits std. dev.: $%2.f" % (profits.std()) print "Max. profit: $%2.f" % (profits.max()) print "Min. profit: $%2.f" % (profits.min()) returns = self.tradesAnalyzer.getPositiveReturns() print "Avg. return: %2.f %%" % (returns.mean() * 100) print "Returns std. dev.: %2.f %%" % (returns.std() * 100) print "Max. return: %2.f %%" % (returns.max() * 100) print "Min. return: %2.f %%" % (returns.min() * 100) print print "Unprofitable trades: %d" % ( self.tradesAnalyzer.getUnprofitableCount()) if self.tradesAnalyzer.getUnprofitableCount() > 0: losses = self.tradesAnalyzer.getLosses() print "Avg. loss: $%2.f" % (losses.mean()) print "Losses std. dev.: $%2.f" % (losses.std()) print "Max. loss: $%2.f" % (losses.min()) print "Min. loss: $%2.f" % (losses.max()) returns = self.tradesAnalyzer.getNegativeReturns() print "Avg. return: %2.f %%" % (returns.mean() * 100) print "Returns std. dev.: %2.f %%" % (returns.std() * 100) print "Max. return: %2.f %%" % (returns.max() * 100) print "Min. return: %2.f %%" % (returns.min() * 100) print "-------------------------------------------------------------------------" def initAnalyzer(self): from pyalgotrade.stratanalyzer import sharpe from pyalgotrade.stratanalyzer import returns from pyalgotrade.stratanalyzer import drawdown from pyalgotrade.stratanalyzer import trades # 1.0) 策略结果 self.returnsAnalyzer = returns.Returns() # 1.1) 夏普比率 self.sharpeRatioAnalyzer = sharpe.SharpeRatio() # 1.2) self.drawdownAnalyzer = drawdown.DrawDown() # 1.3) self.tradesAnalyzer = trades.Trades() self.attachAnalyzer(self.sharpeRatioAnalyzer) self.attachAnalyzer(self.returnsAnalyzer) self.attachAnalyzer(self.tradesAnalyzer) self.attachAnalyzer(self.drawdownAnalyzer)
def initEa(self, timeFrom=None, timeTo=None): feeds = self.getFeeds(timeFrom=timeFrom, timeTo=timeTo) instrument = self.instrument strategy.BacktestingStrategy.__init__(self, feeds[instrument]) self.mid_DEFAULT_MAX_LEN = 10 * DEFAULT_MAX_LEN mid_DEFAULT_MAX_LEN = self.mid_DEFAULT_MAX_LEN #mid 计算ma将使用当天的收盘价格计算 #mid 1) feed = feeds[instrument] dataSeries = feed[instrument] dataSeries.setMaxLen(mid_DEFAULT_MAX_LEN) closeSeries = dataSeries.getCloseDataSeries() #mid 2) prices = closeSeries prices.setMaxLen(mid_DEFAULT_MAX_LEN) self.closePrices = prices #mid follow vars will be used in subclass self.timeFrom = timeFrom self.timeTo = timeTo self.instrument = instrument self.longPosition = None self.shortPosition = None self.buySignal = False self.sellSignal = False #mid follow vars will be used only this class self.__curPositionCost = 0 #mid init position value mid_DEFAULT_MAX_LEN = self.mid_DEFAULT_MAX_LEN self.__position_volume = SequenceDataSeries( maxLen=mid_DEFAULT_MAX_LEN) #mid 当前持有头寸数量 self.__position_cost = SequenceDataSeries( maxLen=mid_DEFAULT_MAX_LEN) #mid 当前持有头寸开仓成本 self.__position_pnl = SequenceDataSeries( maxLen=mid_DEFAULT_MAX_LEN) #mid 当前持有头寸价值 self.__portfolio_value = SequenceDataSeries(maxLen=mid_DEFAULT_MAX_LEN) self.__buy = SequenceDataSeries(maxLen=mid_DEFAULT_MAX_LEN) self.__sell = SequenceDataSeries(maxLen=mid_DEFAULT_MAX_LEN)
class DMACrossOver(strategy.BacktestingStrategy): def __init__(self, feed = None, instrument = '',shortPeriod = 0,longPeriod = 0,money = None,longAllowed=True,shortAllowed=True): strategy.BacktestingStrategy.__init__(self, feed) self.position_cost = 0 #mid init position value mid_DEFAULT_MAX_LEN = 10 * DEFAULT_MAX_LEN self.__instrument = instrument self.__longPosition = None self.__shortPosition = None self.__position_volume = SequenceDataSeries(maxLen = mid_DEFAULT_MAX_LEN) #mid 当前持有头寸数量 self.__position_cost = SequenceDataSeries(maxLen = mid_DEFAULT_MAX_LEN) #mid 当前持有头寸开仓成本 self.__position_pnl = SequenceDataSeries(maxLen = mid_DEFAULT_MAX_LEN) #mid 当前持有头寸价值 self.__portfolio_value = SequenceDataSeries(maxLen = mid_DEFAULT_MAX_LEN) self.__buy = SequenceDataSeries(maxLen = mid_DEFAULT_MAX_LEN) self.__sell = SequenceDataSeries(maxLen = mid_DEFAULT_MAX_LEN) self.__buySignal = False self.__sellSignal = False self.money = money self.longAllowed = True self.shortAllowed = True #mid 计算ma将使用当天的收盘价格计算 #mid 1) dataSeries = feed[instrument] dataSeries.setMaxLen(mid_DEFAULT_MAX_LEN) closeSeries = dataSeries.getCloseDataSeries() #mid 2) prices = closeSeries prices.setMaxLen(mid_DEFAULT_MAX_LEN) #mid 3) self.__sma = ma.SMA(prices, shortPeriod,maxLen=mid_DEFAULT_MAX_LEN) self.__lma = ma.SMA(prices,longPeriod,maxLen=mid_DEFAULT_MAX_LEN) self.i = 0 def getAssetStructure(self): #mid -------------------------------- #mid 当前账户资产结构如下方式获取 #mid Long 和 Short不会同时存在 #mid 在开仓前,若有反向持仓,则此过程查询并输出已持有的反向持仓 broker = self.getBroker() portfolio_value = broker.getEquity() cash = broker.getCash() if self.__shortPosition is not None or self.__longPosition is not None: bars = self.getFeed().getCurrentBars() positions = broker.getPositions() positionsOpenValue = {} positionsCloseValue = {} for key,value in positions.items(): print "key:"+key+",value:"+str(value) bar = bars.getBar(key) openPrice = bar.getOpen() closePrice = bar.getClose() share = broker.getShares(key) positionsOpenValue[key] = openPrice*share positionsCloseValue[key] = closePrice*share print print 'current bar asset structure' print 'open cash %2.f.' % (cash) for key,value in positionsOpenValue.items(): print "key:"+key+",value:"+str(value) print 'close cash %2.f.' % (cash) for key,value in positionsCloseValue.items(): print "key:"+key+",value:"+str(value) print 'portfolio:%2.f' % (portfolio_value) return portfolio_value,cash,sum(positionsCloseValue.values()) return portfolio_value,cash,0 def recordPositions(self): # record position ####################################################################### broker = self.getBroker() position = broker.getPositions() #mid position is dict of share share = broker.getShares(self.__instrument) #mid position is dict of share lastPrice = self.getLastPrice(self.__instrument) portfolio_value = broker.getEquity() #mid 按close价格计算的权益 cash = broker.getCash() position_value = portfolio_value - cash position_pnl = position_value - self.position_cost print print 'cash: %.2f' %(cash) print 'position value: %.2f' % (portfolio_value - cash) print 'mid calc: %.2f' %(lastPrice*share+cash) print 'broker returned: %.2f' %(portfolio_value) curTime = self.getCurrentDateTime() if(False): yLimit = self.money.getShares()*1.1 if(self.i==0): self.__position.append(yLimit) self.i = self.i + 1 elif(self.i==1): self.__position.append(-yLimit) self.i = self.i + 1 else: currentTime = self.getCurrentDateTime() self.__position.appendWithDateTime(currentTime,abs(share)) #self.__position.append(share) else: currentTime = self.getCurrentDateTime() self.__position_volume.appendWithDateTime(currentTime,abs(share)) self.__position_cost.appendWithDateTime(currentTime,abs(self.position_cost)) self.__position_pnl.appendWithDateTime(currentTime,position_pnl) self.__portfolio_value.appendWithDateTime(currentTime,portfolio_value) self.__buy.appendWithDateTime(currentTime,self.__buySignal) self.__sell.appendWithDateTime(currentTime,self.__sellSignal) def getInstrument(self): return self.__instrument def getPortfolio(self): return self.__portfolio_value def getPositionVolume(self): return self.__position_volume def getPositionCost(self): return self.__position_cost def getPositionPnl(self): return self.__position_pnl def getSMA(self): return self.__sma def getLMA(self): return self.__lma def getBuy(self): return self.__buy def getSell(self): return self.__sell def onEnterOk(self, position): execInfo = position.getEntryOrder().getExecutionInfo() portfolio = self.getResult() cash = self.getBroker().getCash() '''mid 以下两种方法都是为了计算持仓成本 由于getEquity()返回的是依据当日close价格计算出来的权益 所以,这个值不能作为持仓成本 持仓成本需要以onEnterOk时bar的open价格计算 所以应使用第二种算法 由于经常有跳开现象,所以依据bar(n-1).close发出的market order, 在bar(n).open执行时通常会有gap出现,表现在position_cost图上时就是持有成本离计划成本会有跳口, ''' if(False):#mid two methods to cacl cost. portfolio_value = self.getBroker().getEquity() self.position_cost = portfolio_value - cash else: feed = self.getFeed() bars = feed.getCurrentBars() bar = bars.getBar(self.__instrument) openPrice = bar.getOpen() closePrice = self.getLastPrice(self.__instrument) #mid lastPrice == closePrice share = self.getBroker().getShares(self.__instrument) self.position_cost = openPrice*share self.info("onEnterOk().current available cash: %.2f,portfolio: %.2f." % (cash,portfolio)) if isinstance(position, strategy.position.LongPosition): self.info("onEnterOK().ExecutionInfo: %s,OPEN LONG %.2f at $%.2f" % (execInfo.getDateTime(),execInfo.getQuantity(),execInfo.getPrice())) elif isinstance(position, strategy.position.ShortPosition): self.info("onEnterOK().ExecutionInfo: %s,OPEN SHORT %.2f at $%.2f" % (execInfo.getDateTime(),execInfo.getQuantity(),execInfo.getPrice())) def onEnterCanceled(self, position): self.info("onEnterCanceled().current available cash: %.2f." % (self.getBroker().getCash())) if isinstance(position, strategy.position.LongPosition): self.__longPosition = None self.info("onEnterCanceled().OPEN LONG cancled.") elif isinstance(position, strategy.position.ShortPosition): self.__shortPosition = None self.info("onEnterCanceled().OPEN SHORT cancled.") def onExitOk(self, position): execInfo = position.getExitOrder().getExecutionInfo() portfolio = self.getResult() cash = self.getBroker().getCash() self.info("onExitOk().current available cash: %.2f,portfolio: %.2f." % (cash,portfolio)) if isinstance(position, strategy.position.LongPosition): self.__longPosition = None self.info("onExitOk().ExecutionInfo: %s,CLOSE LONG %.2f at $%.2f" % (execInfo.getDateTime(),execInfo.getQuantity(),execInfo.getPrice())) elif isinstance(position, strategy.position.ShortPosition): self.__shortPosition = None self.info("onExitOk().ExecutionInfo: %s,CLOSE SHORT %.2f at $%.2f" % (execInfo.getDateTime(),execInfo.getQuantity(),execInfo.getPrice())) def onExitCanceled(self, position): # If the exit was canceled, re-submit it. if isinstance(position, strategy.position.LongPosition): self.__longPosition = None elif isinstance(position, strategy.position.ShortPosition): self.__shortPosition = None def logInfo(self,bars = None): pLong,pShort = 0,0 if(self.__longPosition is not None): pLong = self.__longPosition.getShares() if(self.__shortPosition is not None): pShort = self.__shortPosition.getShares() bar = bars[self.__instrument] pOpen = bar.getOpen() pHigh = bar.getHigh() pLow = bar.getLow() pClose = bar.getClose() pPrice = bar.getPrice() self.info('logInfo().price:%.3f,open:%.2f,high:%.2f,low:%.2f,close:%.2f'%(pPrice,pOpen,pHigh,pLow,pClose)) #self.info('long:%.2f#short:%.2f'%(pLong,pShort)) def run(self): strategy.BacktestingStrategy.run(self) sma = self.getSMA() lma = self.getLMA() buy = self.getBuy() sell = self.getSell() portfolio_value = self.getPortfolio() position_volume = self.getPositionVolume() position_cost = self.getPositionCost() position_pnl = self.getPositionPnl() result = pd.DataFrame({'position_volume':list(position_volume),'position_cost':list(position_cost),'position_pnl':list(position_pnl),'short_ema':list(sma),'long_ema':list(lma), 'buy':list(buy),'sell':list(sell),'portfolio_value':list(portfolio_value)}, columns=['position_volume','position_cost','position_pnl','short_ema','long_ema','buy','sell','portfolio_value'], index=position_volume.getDateTimes()) return result def onBars(self, bars): '''mid 此处是onBars,这个和zipline的概念完全不同 zipline中,需要覆写的是handle_data,这个东西是个tick概念,所以没有OHLC的,只是个price PAT中,每次onBars,都会传入一个newbar的OHLC,此时,要如何按这个OHLC决策,全由你 依据OHLC做完决策后,可以发送交易指令: * Order.Type.MARKET * Order.Type.LIMIT * Order.Type.STOP * Order.Type.STOP_LIMIT 1.市价单,依据下一个bar的openPrice执行命令: self.enterLong() 2.限价单 3.止损单市价单 4.止损限价单 当前似乎没有止盈单 在均线策略中,应该在每个newbar到来时,按closePrice的均线计算指标值,然后发送市价单 1.每个newbar按close价格计算指标,并在下一个bar按open成交 2.每个newbar按open价格计算指标,并在此newbar按open成交 以上1,2的计算逻辑是一致的。如果当前bar的close和下一个bar的open相差无几时,两种算法的回测结果也应相差无几 ''' self.__buySignal,self.__sellSignal = False,False # mid 1)close if(self.longAllowed): if self.__longPosition is not None and not self.__longPosition.exitActive(): #mid 有多仓,检查是否需要平仓 if(cross.cross_below(self.__sma, self.__lma) > 0): print self.info("onBars().Status info,before exitMarket(), LONG POSITION to close %.2f" % (self.__longPosition.getShares())) self.__longPosition.exitMarket() if(self.shortAllowed): if self.__shortPosition is not None and not self.__shortPosition.exitActive(): if(cross.cross_above(self.__sma, self.__lma) > 0): print self.info("onBars().Status info,before exitMarket(), SHORT POSITION to close %.2f" % (self.__shortPosition.getShares())) self.__shortPosition.exitMarket() # mid 2)open if(self.longAllowed): if self.__longPosition is None: #mid 无多仓,检查是否需要开多仓 if cross.cross_above(self.__sma, self.__lma) > 0: # Enter a buy market order. The order is good till canceled. shares = self.money.getShares(strat = self) self.info("onBars().Status info,before enterLong(), LONG POSITION to open %.2f,need amount: %.2f,available amount: %.2f." % (shares,shares*self.getLastPrice(self.__instrument),self.getBroker().getCash() )) self.__longPosition = self.enterLong(self.__instrument, shares, True) self.__buySignal = True if(self.shortAllowed): if self.__shortPosition is None: if cross.cross_below(self.__sma, self.__lma) > 0: # Enter a buy market order. The order is good till canceled. shares = self.money.getShares(strat = self) self.info("onBars().Status info,before enterShort(), SHORT POSITION to open %.2f,need amount: %.2f,available amount: %.2f." % (shares,shares*self.getLastPrice(self.__instrument),self.getBroker().getCash() )) self.__shortPosition = self.enterShort(self.__instrument, shares, True) self.__sellSignal = True self.recordPositions()
def __init__(self, feed, instrument, bollingerlength, numStdDev, closelength, ccMAlength, malength, space): strategy.BacktestingStrategy.__init__(self, feed) self.getBroker().setFillStrategy(DefaultStrategy(None)) self.getBroker().setCommission(TradePercentage(0.002)) self.__instrument = instrument self.__bollingerlength = int(bollingerlength) numStdDev = float(numStdDev) / 10 self.__closelength = int(closelength) self.__ccMAlength = int(ccMAlength) self.__malength = int(malength) self.__longPos = None self.__shortPos = None self.__close = feed[instrument].getCloseDataSeries() self.__open = feed[instrument].getOpenDataSeries() self.__high = feed[instrument].getHighDataSeries() self.__low = feed[instrument].getLowDataSeries() self.__datetime = feed[instrument].getDateTimes() self.__bollinger = bollinger.BollingerBands(self.__close, self.__bollingerlength, int(numStdDev)) self.__UpperBand = self.__bollinger.getUpperBand() self.__LowerBand = self.__bollinger.getLowerBand() self.__MA = SequenceDataSeries() self.__space = int(space) self.__enter = 0 self.__enterLong1 = 0 self.__enterLong2 = 0 self.__enterShort1 = 0 self.__enterShort2 = 0 self.__exitLong1 = 0 self.__exitLong2 = 0 self.__exitShort1 = 0 self.__exitShort1 = 0 #for test ######################################################################### self.__p = SequenceDataSeries() self.__filterCon = SequenceDataSeries() self.__ccMACon1 = SequenceDataSeries() self.__ccMACon2 = SequenceDataSeries() self.__enterCon = SequenceDataSeries() self.__enterLongCon1 = SequenceDataSeries() self.__enterLongCon2 = SequenceDataSeries() self.__enterShortCon1 = SequenceDataSeries() self.__enterShortCon2 = SequenceDataSeries() self.__exitLongCon1 = SequenceDataSeries() self.__exitLongCon2 = SequenceDataSeries() self.__exitShortCon1 = SequenceDataSeries() self.__exitShortCon2 = SequenceDataSeries()
class Macd(SequenceDataSeries): def __init__(self, instrument, dataSeries, fastEMA, slowEMA, signalEMA, maxLen=None): assert (fastEMA > 0) assert (slowEMA > 0) assert (fastEMA < slowEMA) assert (signalEMA > 0) super(Macd, self).__init__(maxLen) self.__instrument = instrument self.__skipNum = max(fastEMA, slowEMA, signalEMA) self.__fastEMAWindow = EMAEventWindow(fastEMA) self.__slowEMAWindow = EMAEventWindow(slowEMA) self.__signalEMAWindow = EMAEventWindow(signalEMA) self.__signal = SequenceDataSeries(maxLen) #dea self.__histogram = SequenceDataSeries(maxLen) #macd self.__cross = SequenceDataSeries( maxLen) #dead cross signals and gold cross signals self.__close_prices = dataSeries.getPriceDataSeries() self.top_divergences = list() self.double_top_divergences = list() self.bottom_divergences = list() self.double_bottom_divergences = list() self.cross_detect = CrossDetect() self.max_limit_detect = MaxLimitDetect self.min_limit_detect = MinLimitDetect self.top_divergence_detect = TopDivergenceDetect() self.bottom_divergence_detect = BottomDivergenceDetect() self.__close_prices.getNewValueEvent().subscribe(self.__onNewValue) def newCross(self, cross_type, cross_date, limit_dif, area, limit_dif_date, macd, macd_date, close, close_date): if cross_type == GOLD: return GoldCross(cross_date, limit_dif, area, limit_dif_date, macd, macd_date, close, close_date) else: return DeathCross(cross_date, limit_dif, area, limit_dif_date, macd, macd_date, close, close_date) def createNewCross(self, current_date, pre_cross_type, current_cross_type, detect): """ 获取三种极值的时间和极值[MACD,CLOSE, DIF] :param current_date: 当前bar的date :param pre_cross_type: 前一个交叉点的类型 :param current_cross_type: 当前交叉点的类型 :param detect: 极值检测类对象 :return: new class """ pre_cross_signal_date = self.getPreSignalDate(pre_cross_type) if pre_cross_signal_date is None: return self.newCross(current_cross_type, current_date, None, None, None, None, None, None, None) dif, dif_date = detect.get_limit_info_in(self, pre_cross_signal_date, current_date) close, close_date = detect.get_close_limit_info_in( self.__close_prices, pre_cross_signal_date, current_date) macd, macd_date = detect.get_limit_info_in(self.__histogram, pre_cross_signal_date, current_date) area = detect.get_sum_info_in(self.__histogram, pre_cross_signal_date, current_date) return self.newCross(current_cross_type, current_date, dif, area, dif_date, macd, macd_date, close, close_date) def getPreSignalDate(self, pre_cross_type): """ 获取dif和dea前一个交叉点的时间 :param pre_cross_type: 前一次交叉的类型[金叉或死叉] :return: """ slength = len(self.__cross) if slength == 0: return None for x in range(slength - 1, -1, -1): if self.__cross[x].type == pre_cross_type: return self.__cross[x].cdate return None def getDif(self): return self def getDea(self): """Returns a :class:`pyalgotrade.dataseries.DataSeries` with the EMA over the MACD.""" return self.__signal def getMacd(self): """Returns a :class:`pyalgotrade.dataseries.DataSeries` with the histogram (the difference between the MACD and the Signal).""" return self.__histogram def __onNewValue(self, dataSeries, dateTime, value): self.__fastEMAWindow.onNewValue(dateTime, value) self.__slowEMAWindow.onNewValue(dateTime, value) fastValue = self.__fastEMAWindow.getValue() slowValue = self.__slowEMAWindow.getValue() if fastValue is None or slowValue is None: diffValue = None else: diffValue = fastValue - slowValue self.__signalEMAWindow.onNewValue(dateTime, diffValue) deaValue = self.__signalEMAWindow.getValue() if diffValue is None or deaValue is None: macdValue = None else: macdValue = 2 * (diffValue - deaValue) self.appendWithDateTime(dateTime, diffValue) #dif self.__signal.appendWithDateTime(dateTime, deaValue) #dea self.__histogram.appendWithDateTime(dateTime, macdValue) #macd if len(self) >= self.__skipNum: preMacdValue = self.__histogram[-2] if self.cross_detect.is_cross(preMacdValue, macdValue, GoldCross): cross = self.createNewCross(dateTime, DEATH, GOLD, self.min_limit_detect) log.debug("code:%s 类型:%s, 日期:%s, dif:%s, area:%s, dif date:%s, macd:%s, macd date:%s, close:%s, close date:%s" %\ (self.__instrument, cross.type, cross.cdate, cross.dif, cross.area, cross.dif_date, cross.macd, cross.macd_date, cross.close, cross.close_date)) self.__cross.appendWithDateTime(dateTime, cross) #self.bottom_divergences = self.bottom_divergence_detect.get_divergences(self.__cross, self, self.__histogram) self.double_bottom_divergences = self.bottom_divergence_detect.get_double_divergences( self.__cross, self, self.__histogram) elif self.cross_detect.is_cross(preMacdValue, macdValue, DeathCross): cross = self.createNewCross(dateTime, GOLD, DEATH, self.max_limit_detect) log.debug("code:%s 类型:%s, 日期:%s, dif:%s, area:%s, dif date:%s, macd:%s, macd date:%s, close:%s, close date:%s" %\ (self.__instrument, cross.type, cross.cdate, cross.dif, cross.area, cross.dif_date, cross.macd, cross.macd_date, cross.close, cross.close_date)) self.__cross.appendWithDateTime(dateTime, cross) #self.top_divergences = self.top_divergence_detect.get_divergences(self.__cross, self, self.__histogram) self.double_top_divergences = self.top_divergence_detect.get_double_divergences( self.__cross, self, self.__histogram) else: log.debug("%s 没有信号" % dateTime) else: log.debug("%s 还需要skip" % dateTime)
def __init_pivot_levels(levels, maxLen=None): return {l: SequenceDataSeries(maxLen) for l in levels}
def initEa(self, timeFrom=None, timeTo=None): self.results = {} feed = self.getFeedNew(timeFrom=timeFrom, timeTo=timeTo) self.mid_DEFAULT_MAX_LEN = 10 * DEFAULT_MAX_LEN mid_DEFAULT_MAX_LEN = self.mid_DEFAULT_MAX_LEN #mid set init cash cash_or_brk = 1000000 volumeLimit = 0.5 #mid used to calculate available volume for an order: availableVolume = volumeLeft * volumeLimit #mid set fillstrategy fillStrategy = fillstrategy.DefaultStrategy(volumeLimit=volumeLimit) broker = backtesting.Broker(cash_or_brk, feed) broker.setFillStrategy(fillStrategy) #mid init base strategy.BacktestingStrategy.__init__(self, feed, broker) #mid 计算ma将使用当天的收盘价格计算 #mid 1) self.closePrices = {} self.longPosition = {} self.shortPosition = {} self.buySignal = {} self.sellSignal = {} self.timeFrom = timeFrom self.timeTo = timeTo #mid follow vars will be used only this class self.__portfolio_value = SequenceDataSeries( maxLen=mid_DEFAULT_MAX_LEN) #mid 记录资产组合(cash + 各个持仓证券的价值和)的合计价值变化 self.__available_cash = SequenceDataSeries( maxLen=mid_DEFAULT_MAX_LEN) #mid 记录资产组合的现金变化 self.__long_exitBar_pnl = {} #mid 多头平仓bar产生的pnl self.__long_position_volume = {} #mid 当前多头数量 self.__long_position_cost = {} #mid 当前持有多头开仓成本 self.__long_position_currentBar_pnl = {} #mid 当前持有多头当前bar产生的pnl self.__long_position_pnl = {} #mid 当前多头累计产生的pnl self.__short_exitBar_pnl = {} self.__short_position_volume = {} #mid 当前持有头寸数量 self.__short_position_cost = {} #mid 当前持有头寸开仓成本 self.__short_position_currentBar_pnl = {} #mid 当前持有头寸价值 self.__short_position_pnl = {} self.__position_cumulativePNL = { } #mid 当前 symbol 持有头寸cumulative pnl 价值(包括该symbol多头和空头的所有开仓平仓产生的pnl) self.__buy = {} self.__sell = {} for instrument in self.instruments: dataSeries = feed[instrument] dataSeries.setMaxLen(mid_DEFAULT_MAX_LEN) closeSeries = dataSeries.getCloseDataSeries() #mid 2) prices = closeSeries prices.setMaxLen(mid_DEFAULT_MAX_LEN) #mid follow vars will be used in subclass self.closePrices[instrument] = prices self.longPosition[instrument] = None self.shortPosition[instrument] = None self.buySignal[instrument] = False self.sellSignal[instrument] = False #mid follow vars will be used only this class self.__long_exitBar_pnl[instrument] = None self.__short_exitBar_pnl[instrument] = None self.__long_position_volume[instrument] = SequenceDataSeries( maxLen=mid_DEFAULT_MAX_LEN) #mid 当前持有头寸数量 self.__short_position_volume[instrument] = SequenceDataSeries( maxLen=mid_DEFAULT_MAX_LEN) #mid 当前持有头寸数量 self.__long_position_cost[instrument] = SequenceDataSeries( maxLen=mid_DEFAULT_MAX_LEN) #mid 当前持有头寸开仓成本 self.__short_position_cost[instrument] = SequenceDataSeries( maxLen=mid_DEFAULT_MAX_LEN) #mid 当前持有头寸开仓成本 self.__long_position_currentBar_pnl[ instrument] = SequenceDataSeries( maxLen=mid_DEFAULT_MAX_LEN) #mid 当前持有头寸价值 self.__short_position_currentBar_pnl[ instrument] = SequenceDataSeries( maxLen=mid_DEFAULT_MAX_LEN) #mid 当前持有头寸价值 self.__short_position_pnl[instrument] = SequenceDataSeries( maxLen=mid_DEFAULT_MAX_LEN) self.__long_position_pnl[instrument] = SequenceDataSeries( maxLen=mid_DEFAULT_MAX_LEN) self.__position_cumulativePNL[instrument] = SequenceDataSeries( maxLen=mid_DEFAULT_MAX_LEN) self.__buy[instrument] = SequenceDataSeries( maxLen=mid_DEFAULT_MAX_LEN) self.__sell[instrument] = SequenceDataSeries( maxLen=mid_DEFAULT_MAX_LEN)
def __init__(self, feed=None, instrument='', shortPeriod=0, longPeriod=0, money=None, longAllowed=True, shortAllowed=True): strategy.BacktestingStrategy.__init__(self, feed) self.position_cost = 0 #mid init position value mid_DEFAULT_MAX_LEN = 10 * DEFAULT_MAX_LEN self.__instrument = instrument self.__longPosition = None self.__shortPosition = None self.__position_volume = SequenceDataSeries( maxLen=mid_DEFAULT_MAX_LEN) #mid 当前持有头寸数量 self.__position_cost = SequenceDataSeries( maxLen=mid_DEFAULT_MAX_LEN) #mid 当前持有头寸开仓成本 self.__position_pnl = SequenceDataSeries( maxLen=mid_DEFAULT_MAX_LEN) #mid 当前持有头寸价值 self.__portfolio_value = SequenceDataSeries(maxLen=mid_DEFAULT_MAX_LEN) self.__buy = SequenceDataSeries(maxLen=mid_DEFAULT_MAX_LEN) self.__sell = SequenceDataSeries(maxLen=mid_DEFAULT_MAX_LEN) self.__buySignal = False self.__sellSignal = False self.money = money self.longAllowed = True self.shortAllowed = True #mid 计算ma将使用当天的收盘价格计算 #mid 1) dataSeries = feed[instrument] dataSeries.setMaxLen(mid_DEFAULT_MAX_LEN) closeSeries = dataSeries.getOpenDataSeries() #mid 2) prices = closeSeries prices.setMaxLen(mid_DEFAULT_MAX_LEN) #mid 3) self.__sma = ma.SMA(prices, shortPeriod, maxLen=mid_DEFAULT_MAX_LEN) self.__lma = ma.SMA(prices, longPeriod, maxLen=mid_DEFAULT_MAX_LEN) self.i = 0
class bollinger_band(strategy.BacktestingStrategy): def __init__(self, feed, instrument, bollingerlength, numStdDev): strategy.BacktestingStrategy.__init__(self, feed) self.getBroker().setFillStrategy(DefaultStrategy(None)) self.getBroker().setCommission(TradePercentage(0)) self.__instrument = instrument self.__bollingerlength = int(bollingerlength) self.__close = feed[instrument].getPriceDataSeries() numStdDev = float(numStdDev) / 10 self.__longPos = [] self.__macd=macd.MACD(self.__close,50,150,10) self.__bollinger = bollinger.BollingerBands(self.__macd, self.__bollingerlength, int(numStdDev)) self.__UpperBand = self.__bollinger.getUpperBand() self.__LowerBand = self.__bollinger.getLowerBand() self.__position = SequenceDataSeries() self.__circ=5 def getPrice(self): return self.__prices def getMACD(self): return self.__macd def getBollingerBands(self): return self.__bollinger def testCon(self): # record position ####################################################################### if len(self.__longPos) > 0: self.__position.append(len(self.__longPos)) elif len(self.__longPos)==0 : self.__position.append(0) #print(0) def getTest(self): return self.__position def onBars(self, bars): bar = bars[self.__instrument] lower = self.__bollinger.getLowerBand()[-1] upper = self.__bollinger.getUpperBand()[-1] # print(self.getActivePositions()) if lower is None: return self.testCon() if len(self.__longPos)> 0: if self.exitLongSignal(): for pos in self.__longPos: pos.exitMarket() elif len(self.__longPos)<5 : if self.enterLongSignal(): shares =1 # self.__longPos. self.__longPos.append(self.enterLong(self.__instrument, shares)) def enterLongSignal (self) : if self.__UpperBand[-1-self.__circ] is None: return False m1 = 0 for i in range(self.__circ): if self.__macd[-i-1] <= self.__LowerBand[-i-2]: m1 += 1 if m1 >= self.__circ-1 and cross.cross_above(self.__macd,self.__LowerBand)>0: return True else: return False def enterShortSignal(self) : if self.__UpperBand[-1-self.__circ] is None: return False m1 = 0 for i in range(self.__circ): if self.__macd[-i-1] >= self.__UpperBand[-i-2]: m1 += 1 if m1 >= self.__circ-1 and cross.cross_below(self.__macd,self.__UpperBand)>0: return True else: return False def exitLongSignal(self) : if self.__UpperBand[-1-self.__circ] is None: return False m1 = 0 for i in range(self.__circ): if self.__macd[-i-1] >= self.__UpperBand[-i-2]: m1 += 1 if m1 >= self.__circ-1 and cross.cross_below(self.__macd,self.__UpperBand)>0: return True else: return False def exitShortSignal(self): if self.__UpperBand[-1-self.__circ] is None: return False m1 = 0 for i in range(self.__circ): if self.__macd[-i-1] <= self.__LowerBand[-i-2]: m1 += 1 if m1 >= self.__circ-1 and cross.cross_above(self.__macd,self.__LowerBand)>0: return True else: return False def onEnterCanceled(self, position): if len(self.__longPos)>0: if self.__longPos[-1] == position: del self.__longPos[-1] #else: #assert(False) def onEnterOK(self,position): pass def onExitOk(self, position): if isinstance(position,LongPosition): self.__longPos = [] else: assert(False) def onExitCanceled(self, position): position.exitMarket()
def metric_goquant_to_backtest(metric_data_series): ret = SequenceDataSeries() for i, v in metric_data_series.items(): ret.appendWithDateTime(i, v) return ret
class SingleMA(strategy.BacktestingStrategy): def __init__(self, feed, instrument, n, initialCash = 1000000): strategy.BacktestingStrategy.__init__(self, feed, initialCash) self.__instrument = instrument self.getBroker().setFillStrategy(DefaultStrategy(None)) self.getBroker().setCommission(TradePercentage(0.001)) self.__position = None self.__prices = feed[instrument].getPriceDataSeries() self.__malength = int(n) self.__ma = ma.SMA(self.__prices, self.__malength) self.__pos = SequenceDataSeries() # record signal def getPrice(self): return self.__prices def getMA(self): return self.__ma def testCon(self): if self.__position is not None: self.__pos.append(1) elif self.__position is None: self.__pos.append(0) def getPos(self): return self.__pos def onEnterCanceled(self, position): self.__position = None def onEnterOk(self, position): execInfo = position.getEntryOrder().getExecutionInfo() instrumentInfo = position.getInstrument() self.info("BUY %s at $%.2f" % (instrumentInfo, execInfo.getPrice())) def onExitOk(self, position): execInfo = position.getExitOrder().getExecutionInfo() instrumentInfo = position.getInstrument() self.info("SELL %s at $%.2f" % (instrumentInfo, execInfo.getPrice())) self.__position = None def onExitCancelled(self, position): self.__position.exitMarket() def onBars(self, bars): closePrice = bars[self.__instrument].getPrice() if self.__ma[-1] is None: return self.testCon() if self.__position is not None: if not self.__position.exitActive() and closePrice < self.__ma[-1]: self.__position.exitMarket() if self.__position is None: if closePrice > self.__ma[-1]: shares = int(self.getBroker().getEquity() * 0.9 / closePrice) self.__position = self.enterLong(self.__instrument, shares)
def initEa(self,timeFrom=None,timeTo=None): self.results = {} feed = self.getFeedNew(timeFrom = timeFrom,timeTo = timeTo) self.mid_DEFAULT_MAX_LEN = 10 * DEFAULT_MAX_LEN mid_DEFAULT_MAX_LEN = self.mid_DEFAULT_MAX_LEN #mid set init cash cash_or_brk = 1000000 volumeLimit = 0.5 #mid used to calculate available volume for an order: availableVolume = volumeLeft * volumeLimit #mid set fillstrategy fillStrategy = fillstrategy.DefaultStrategy(volumeLimit = volumeLimit) broker = backtesting.Broker(cash_or_brk, feed) broker.setFillStrategy(fillStrategy) #mid init base strategy.BacktestingStrategy.__init__(self, feed,broker) #mid 计算ma将使用当天的收盘价格计算 #mid 1) self.closePrices = {} self.longPosition = {} self.shortPosition = {} self.buySignal = {} self.sellSignal = {} self.timeFrom = timeFrom self.timeTo = timeTo #mid follow vars will be used only this class self.__portfolio_value = SequenceDataSeries(maxLen = mid_DEFAULT_MAX_LEN) self.__available_cash = SequenceDataSeries(maxLen = mid_DEFAULT_MAX_LEN) self.__exitBar_position_pnl = {} self.__curLongPositionCost = {} #mid init position value self.__curShortPositionCost = {} #mid init position value self.__position_volume = {} #mid 当前持有头寸数量 self.__position_cost = {} #mid 当前持有头寸开仓成本 self.__position_pnl = {} #mid 当前持有头寸价值 self.__position_cumulativePNL = {} #mid 当前 symbol 持有头寸cumulative pnl 价值 self.__buy = {} self.__sell = {} for instrument in self.instruments: dataSeries = feed[instrument] dataSeries.setMaxLen(mid_DEFAULT_MAX_LEN) closeSeries = dataSeries.getCloseDataSeries() #mid 2) prices = closeSeries prices.setMaxLen(mid_DEFAULT_MAX_LEN) #mid follow vars will be used in subclass self.closePrices[instrument] = prices self.longPosition[instrument] = None self.shortPosition[instrument] = None self.buySignal[instrument] = False self.sellSignal[instrument] = False #mid follow vars will be used only this class self.__curLongPositionCost[instrument] = 0 #mid init position value self.__curShortPositionCost[instrument] = 0 self.__exitBar_position_pnl[instrument] = None #mid init position value self.__position_volume[instrument] = SequenceDataSeries(maxLen = mid_DEFAULT_MAX_LEN) #mid 当前持有头寸数量 self.__position_cost[instrument] = SequenceDataSeries(maxLen = mid_DEFAULT_MAX_LEN) #mid 当前持有头寸开仓成本 self.__position_pnl[instrument] = SequenceDataSeries(maxLen = mid_DEFAULT_MAX_LEN) #mid 当前持有头寸价值 self.__position_cumulativePNL[instrument] = SequenceDataSeries(maxLen = mid_DEFAULT_MAX_LEN) self.__buy[instrument] = SequenceDataSeries(maxLen = mid_DEFAULT_MAX_LEN) self.__sell[instrument] = SequenceDataSeries(maxLen = mid_DEFAULT_MAX_LEN)
class midBaseStrategy(strategy.BacktestingStrategy): def getFeeds(self, timeFrom=None, timeTo=None): import os, sys xpower = os.path.abspath( os.path.join(os.path.dirname(__file__), os.pardir, os.pardir, os.pardir, 'midProjects', 'histdata')) sys.path.append(xpower) import dataCenter as dataCenter self.dataCenter = dataCenter.dataCenter() feeds = self.dataCenter.getFeedsForPAT(dataProvider=self.dataProvider, storageType=self.storageType, instruments=self.instruments, period=self.period, timeTo=timeTo, timeFrom=timeFrom) return feeds def getFeedNew(self, timeFrom=None, timeTo=None): '''mid should not be named the same with base class''' import os, sys xpower = os.path.abspath( os.path.join(os.path.dirname(__file__), os.pardir, os.pardir, os.pardir, 'midProjects', 'histdata')) sys.path.append(xpower) import dataCenter as dataCenter self.dataCenter = dataCenter.dataCenter() feed = self.dataCenter.getFeedForPAT(dataProvider=self.dataProvider, storageType=self.storageType, instruments=self.instruments, period=self.period, timeTo=timeTo, timeFrom=timeFrom) return feed def initEa(self, timeFrom=None, timeTo=None): self.results = {} feed = self.getFeedNew(timeFrom=timeFrom, timeTo=timeTo) self.mid_DEFAULT_MAX_LEN = 10 * DEFAULT_MAX_LEN mid_DEFAULT_MAX_LEN = self.mid_DEFAULT_MAX_LEN #mid set init cash cash_or_brk = 1000000 volumeLimit = 0.5 #mid used to calculate available volume for an order: availableVolume = volumeLeft * volumeLimit #mid set fillstrategy fillStrategy = fillstrategy.DefaultStrategy(volumeLimit=volumeLimit) broker = backtesting.Broker(cash_or_brk, feed) broker.setFillStrategy(fillStrategy) #mid init base strategy.BacktestingStrategy.__init__(self, feed, broker) #mid 计算ma将使用当天的收盘价格计算 #mid 1) self.closePrices = {} self.longPosition = {} self.shortPosition = {} self.buySignal = {} self.sellSignal = {} self.timeFrom = timeFrom self.timeTo = timeTo #mid follow vars will be used only this class self.__portfolio_value = SequenceDataSeries( maxLen=mid_DEFAULT_MAX_LEN) #mid 记录资产组合(cash + 各个持仓证券的价值和)的合计价值变化 self.__available_cash = SequenceDataSeries( maxLen=mid_DEFAULT_MAX_LEN) #mid 记录资产组合的现金变化 self.__long_exitBar_pnl = {} #mid 多头平仓bar产生的pnl self.__long_position_volume = {} #mid 当前多头数量 self.__long_position_cost = {} #mid 当前持有多头开仓成本 self.__long_position_currentBar_pnl = {} #mid 当前持有多头当前bar产生的pnl self.__long_position_pnl = {} #mid 当前多头累计产生的pnl self.__short_exitBar_pnl = {} self.__short_position_volume = {} #mid 当前持有头寸数量 self.__short_position_cost = {} #mid 当前持有头寸开仓成本 self.__short_position_currentBar_pnl = {} #mid 当前持有头寸价值 self.__short_position_pnl = {} self.__position_cumulativePNL = { } #mid 当前 symbol 持有头寸cumulative pnl 价值(包括该symbol多头和空头的所有开仓平仓产生的pnl) self.__buy = {} self.__sell = {} for instrument in self.instruments: dataSeries = feed[instrument] dataSeries.setMaxLen(mid_DEFAULT_MAX_LEN) closeSeries = dataSeries.getCloseDataSeries() #mid 2) prices = closeSeries prices.setMaxLen(mid_DEFAULT_MAX_LEN) #mid follow vars will be used in subclass self.closePrices[instrument] = prices self.longPosition[instrument] = None self.shortPosition[instrument] = None self.buySignal[instrument] = False self.sellSignal[instrument] = False #mid follow vars will be used only this class self.__long_exitBar_pnl[instrument] = None self.__short_exitBar_pnl[instrument] = None self.__long_position_volume[instrument] = SequenceDataSeries( maxLen=mid_DEFAULT_MAX_LEN) #mid 当前持有头寸数量 self.__short_position_volume[instrument] = SequenceDataSeries( maxLen=mid_DEFAULT_MAX_LEN) #mid 当前持有头寸数量 self.__long_position_cost[instrument] = SequenceDataSeries( maxLen=mid_DEFAULT_MAX_LEN) #mid 当前持有头寸开仓成本 self.__short_position_cost[instrument] = SequenceDataSeries( maxLen=mid_DEFAULT_MAX_LEN) #mid 当前持有头寸开仓成本 self.__long_position_currentBar_pnl[ instrument] = SequenceDataSeries( maxLen=mid_DEFAULT_MAX_LEN) #mid 当前持有头寸价值 self.__short_position_currentBar_pnl[ instrument] = SequenceDataSeries( maxLen=mid_DEFAULT_MAX_LEN) #mid 当前持有头寸价值 self.__short_position_pnl[instrument] = SequenceDataSeries( maxLen=mid_DEFAULT_MAX_LEN) self.__long_position_pnl[instrument] = SequenceDataSeries( maxLen=mid_DEFAULT_MAX_LEN) self.__position_cumulativePNL[instrument] = SequenceDataSeries( maxLen=mid_DEFAULT_MAX_LEN) self.__buy[instrument] = SequenceDataSeries( maxLen=mid_DEFAULT_MAX_LEN) self.__sell[instrument] = SequenceDataSeries( maxLen=mid_DEFAULT_MAX_LEN) def getAssetStructure(self): #mid -------------------------------- #mid 当前账户资产结构如下方式获取 #mid Long 和 Short不会同时存在 #mid 在开仓前,若有反向持仓,则此过程查询并输出已持有的反向持仓 broker = self.getBroker() portfolio_value = broker.getEquity() cash = broker.getCash() if self.shortPosition is not None or self.longPosition is not None: bars = self.getFeed().getCurrentBars() positions = broker.getPositions() positionsOpenValue = {} positionsCloseValue = {} for key, value in positions.items(): print "key:" + key + ",value:" + str(value) bar = bars.getBar(key) openPrice = bar.getOpen() closePrice = bar.getClose() share = broker.getShares(key) positionsOpenValue[key] = openPrice * share positionsCloseValue[key] = closePrice * share print print 'current bar asset structure' print 'open cash %2.f.' % (cash) for key, value in positionsOpenValue.items(): print "key:" + key + ",value:" + str(value) print 'close cash %2.f.' % (cash) for key, value in positionsCloseValue.items(): print "key:" + key + ",value:" + str(value) print 'portfolio:%2.f' % (portfolio_value) return portfolio_value, cash, sum(positionsCloseValue.values()) return portfolio_value, cash, 0 def sampleSub01(self, instrument): """mid not called anywhere because of open price gap,method below is not right. """ broker = self.getBroker() a = broker.getEquity() b = self.getResult() lastOpenPrice = None lastClosePrice = None bar = self.getFeed().getLastBar(instrument) if bar is not None: lastOpenPrice = bar.getOpen() lastClosePrice = bar.getClose() #lastPrice = self.getLastPrice(instrument) pnl = (lastClosePrice - lastOpenPrice) * share else: pnl = 0 #mid instrument is dislisted. if (len(self.__position_cumulativePNL[instrument]) > 0): lastCumulativePNL = self.__position_cumulativePNL[instrument][-1] else: lastCumulativePNL = 0 def recordAccount(self): # record position ####################################################################### broker = self.getBroker() curTime = self.getCurrentDateTime() currentTime = self.getCurrentDateTime() cash = broker.getCash(includeShort=False) portfolio_value = broker.getEquity() #mid 按close价格计算的权益 print self.info("onBars().recordAccount().Current time:%s" % (str(currentTime))) self.info("onBars().recordAccount().----portfolio value: %.2f" % (portfolio_value)) self.info("onBars().recordAccount().----cash in portfolio: %.2f" % (cash)) self.__portfolio_value.appendWithDateTime(currentTime, portfolio_value) self.__available_cash.appendWithDateTime(currentTime, cash) totalCumulativePNL = 0 time = self.getCurrentDateTime() if (time == dt.datetime(2010, 12, 22, 0, 0)): a = 8 for instrument in self.instruments: lastClosePrice = self.getLastPrice(instrument) if (lastClosePrice is None): continue #position_value = lastClosePrice*share longPosition = self.longPosition[instrument] longQuantity = 0 longPnl = 0 longStandingCurBarPnl = 0 longValue = 0 longCost = 0 shortPosition = self.shortPosition[instrument] shortQuantity = 0 shortPnl = 0 shortStandingCurBarPnl = 0 shortValue = 0 shortCost = 0 if (longPosition): entryInfo = longPosition.getEntryOrder() execInfo = entryInfo.getExecutionInfo() if (execInfo): longPnl = longPosition.getPnL() longStandingCurBarPnl = longPnl - self.__lastLongPnl longQuantity = longPosition.getQuantity() longCostPrice = execInfo.getPrice() longCost = longQuantity * longCostPrice self.__lastLongPnl = longPnl if (shortPosition): entryInfo = shortPosition.getEntryOrder() execInfo = entryInfo.getExecutionInfo() if (execInfo): shortPnl = shortPosition.getPnL() shortStandingCurBarPnl = shortPnl - self.__lastShortPnl shortQuantity = shortPosition.getQuantity() shortCostPrice = execInfo.getPrice() shortCost = shortQuantity * shortCostPrice self.__lastShortPnl = shortPnl if (self.__long_exitBar_pnl[instrument]): self.__long_position_currentBar_pnl[ instrument].appendWithDateTime( currentTime, self.__long_exitBar_pnl[instrument]) self.__long_exitBar_pnl[instrument] = None else: self.__long_position_currentBar_pnl[ instrument].appendWithDateTime(currentTime, longStandingCurBarPnl) if (self.__short_exitBar_pnl[instrument]): self.__short_position_currentBar_pnl[ instrument].appendWithDateTime( currentTime, self.__short_exitBar_pnl[instrument]) self.__short_exitBar_pnl[instrument] = None else: self.__short_position_currentBar_pnl[ instrument].appendWithDateTime(currentTime, shortStandingCurBarPnl) #self.__short_position_pnl[instrument].appendWithDateTime(currentTime,shortCurBarPnl) self.__long_position_pnl[instrument].appendWithDateTime( currentTime, longPnl) self.__short_position_pnl[instrument].appendWithDateTime( currentTime, shortPnl) self.__long_position_cost[instrument].appendWithDateTime( currentTime, longCost) self.__short_position_cost[instrument].appendWithDateTime( currentTime, shortCost) self.__long_position_volume[instrument].appendWithDateTime( currentTime, longQuantity) self.__short_position_volume[instrument].appendWithDateTime( currentTime, shortQuantity) self.__buy[instrument].appendWithDateTime( currentTime, self.buySignal[instrument]) self.__sell[instrument].appendWithDateTime( currentTime, self.sellSignal[instrument]) cumulativePNL = 0 longCurBarPnl = self.__long_position_currentBar_pnl[instrument][-1] shortCurBarPnl = self.__short_position_currentBar_pnl[instrument][ -1] currentBarPnl = longCurBarPnl + shortCurBarPnl if (len(self.__position_cumulativePNL[instrument]) > 0): lastCumulativePNL = self.__position_cumulativePNL[instrument][ -1] cumulativePNL = lastCumulativePNL + currentBarPnl else: cumulativePNL = currentBarPnl self.__position_cumulativePNL[instrument].appendWithDateTime( currentTime, cumulativePNL) """mid 如果当前bar有某个position在open price被closed掉,则当前bar的position_pnl是0. 在当前bar的openprice和上一bar的closeprice之间没有gap时,这个算法是合理的,但是,gap往往是存在的, 所以,据此计算的barPnl在exitbar上会有gap导致的误差 在此特别处理exitbar """ """ if(self.__exitBar_position_pnl[instrument] is not None): currentExitedPositionPnl = self.__exitBar_position_pnl[instrument] lastPositionPnl = self.__position_pnl[instrument][-2] currentBarExitedPnl = currentExitedPositionPnl - lastPositionPnl self.__exitBar_position_pnl[instrument] = None currentBarPnl = currentBarPnl + currentBarExitedPnl if(len(self.__position_cumulativePNL[instrument])>0): lastCumulativePNL = self.__position_cumulativePNL[instrument][-1] cumulativePNL = lastCumulativePNL + currentBarPnl else: cumulativePNL = currentBarPnl self.__position_cumulativePNL[instrument].appendWithDateTime(currentTime,cumulativePNL) """ if (True): self.info("onBars().recordAccount().--------%s" % (instrument)) self.info( "onBars().recordAccount().--------mid current bar longPNL: %.3f" % (longCurBarPnl)) self.info( "onBars().recordAccount().--------mid current bar longQuantity:%.3f" % (longQuantity)) self.info( "onBars().recordAccount().--------mid current bar longValue: %.3f" % (longValue)) self.info( "onBars().recordAccount().--------mid current bar longCost: %.3f" % (longCost)) self.info( "onBars().recordAccount().--------mid current bar shortPNL: %.3f" % (shortPnl)) self.info( "onBars().recordAccount().--------mid current bar shortQuantity:%.3f" % (shortQuantity)) self.info( "onBars().recordAccount().--------mid calculated position value: %.3f" % (shortValue)) self.info( "onBars().recordAccount().--------mid calculated shortPnl: %.3f" % (shortCost)) self.info( "onBars().recordAccount().--------mid CumulativePNL: %.3f" % (cumulativePNL)) totalCumulativePNL = totalCumulativePNL + cumulativePNL if (abs(1000000 - (portfolio_value - totalCumulativePNL)) > 0.00000001): self.info("onBars().recordAccount().--------mid initCash: %.3f" % (portfolio_value - totalCumulativePNL)) a = 8 def getPortfolioValue(self): return self.__portfolio_value def getAvailableCash(self): return self.__available_cash def getCurInstrument(self): return self.curInstrument def getPositionValue(self, instrument): return self.__position_cumulativePNL[instrument] def getLongVolume(self, instrument): return self.__long_position_volume[instrument] def getShortVolume(self, instrument): return self.__short_position_volume[instrument] def getLongCost(self, instrument): return self.__long_position_cost[instrument] def getShortCost(self, instrument): return self.__short_position_cost[instrument] def getLongPnl(self, instrument): return self.__long_position_pnl[instrument] def getShortPnl(self, instrument): return self.__short_position_pnl[instrument] def getBuy(self, instrument): return self.__buy[instrument] def getSell(self, instrument): return self.__sell[instrument] def onEnterOk(self, position): '''mid 由于getEquity()返回的是依据当日close价格计算出来的权益 所以,这个值不能作为持仓成本 持仓成本需要以onEnterOk时bar的open价格计算 由于经常有跳开现象,所以依据bar(n-1).close发出的market order, 在bar(n).open执行时通常会有gap出现,表现在position_cost图上时就是持有成本离计划成本会有跳口, ''' print currentTime = self.getCurrentDateTime() execInfo = position.getEntryOrder().getExecutionInfo() self.info("onEnterOK().ExecutionInfo.Current time: %s" % (execInfo.getDateTime())) #mid 1)record the position cost instrument = position.getInstrument() feed = self.getFeed() bars = feed.getCurrentBars() bar = bars.getBar(instrument) openPrice = bar.getOpen() closePrice = self.getLastPrice( instrument) #mid lastPrice == closePrice #mid 2)log account info after enterOKed. execInfo = position.getEntryOrder().getExecutionInfo() portfolio = self.getResult() cash = self.getBroker().getCash() self.info("onEnterOk().symbol:%s" % (instrument)) self.info("onEnterOk().current available cash: %.2f,portfolio: %.2f." % (cash, portfolio)) if isinstance(position, strategy.position.LongPosition): self.__lastLongPnl = 0 self.info("onEnterOK().ExecutionInfo: %s,OPEN LONG %.2f at $%.2f" % (execInfo.getDateTime(), execInfo.getQuantity(), execInfo.getPrice())) elif isinstance(position, strategy.position.ShortPosition): self.__lastShortPnl = 0 self.info( "onEnterOK().ExecutionInfo: %s,OPEN SHORT %.2f at $%.2f" % (execInfo.getDateTime(), execInfo.getQuantity(), execInfo.getPrice())) def onEnterCanceled(self, position): instrument = position.getInstrument() self.info("onEnterCanceled().current available cash: %.2f." % (self.getBroker().getCash())) if isinstance(position, strategy.position.LongPosition): self.longPosition[instrument] = None self.info("onEnterCanceled().OPEN LONG cancled.") elif isinstance(position, strategy.position.ShortPosition): self.shortPosition[instrument] = None self.info("onEnterCanceled().OPEN SHORT cancled.") def onExitOk(self, position): exitInfo = position.getExitOrder().getExecutionInfo() entryInfo = position.getEntryOrder().getExecutionInfo() instrument = position.getInstrument() print currentTime = self.getCurrentDateTime() self.info("onExitOk().ExecutionInfo.Current time: %s" % (exitInfo.getDateTime())) self.info("onExitOk().instrument:%s." % (instrument)) exitQuantity = exitInfo.getQuantity() exitPrice = exitInfo.getPrice() exitAmount = exitQuantity * exitPrice entryQuantity = entryInfo.getQuantity() entryPrice = entryInfo.getPrice() entryCost = entryQuantity * entryPrice #self.sampleSub01(instrument) if isinstance(position, strategy.position.LongPosition): positionCost = entryCost longPnl = position.getPnL() longCurBarPnl = longPnl - self.__lastLongPnl #self.__long_position_pnl[instrument].appendWithDateTime(currentTime,longCurBarPnl) self.__long_exitBar_pnl[instrument] = longCurBarPnl self.longPosition[instrument] = None self.info("onExitOk().ExecutionInfo: %s,CLOSE LONG %.2f at $%.2f" % (exitInfo.getDateTime(), exitQuantity, exitPrice)) elif isinstance(position, strategy.position.ShortPosition): positionCost = entryCost shortPnl = position.getPnL() shortCurBarPnl = shortPnl - self.__lastShortPnl #self.__long_position_pnl[instrument].appendWithDateTime(currentTime,longCurBarPnl) self.__short_exitBar_pnl[instrument] = shortCurBarPnl self.shortPosition[instrument] = None self.info("onExitOk().ExecutionInfo: %s,CLOSE LONG %.2f at $%.2f" % (exitInfo.getDateTime(), exitQuantity, exitPrice)) def onExitCanceled(self, position): # If the exit was canceled, re-submit it. if isinstance(position, strategy.position.LongPosition): self.longPosition[instrument] = None elif isinstance(position, strategy.position.ShortPosition): self.shortPosition[instrument] = None def logInfo(self, bars=None): pLong, pShort = 0, 0 if (self.longPosition is not None): pLong = self.longPosition.getShares() if (self.shortPosition is not None): pShort = self.shortPosition.getShares() bar = bars[self.instrument] pOpen = bar.getOpen() pHigh = bar.getHigh() pLow = bar.getLow() pClose = bar.getClose() pPrice = bar.getPrice() self.info( 'logInfo().price:%.3f,open:%.2f,high:%.2f,low:%.2f,close:%.2f' % (pPrice, pOpen, pHigh, pLow, pClose)) #self.info('long:%.2f#short:%.2f'%(pLong,pShort)) def closePosition(self): for instrument in self.instruments: if (self.longPosition[instrument] is not None and self.sellSignal[instrument] == True and not self.longPosition[instrument].exitActive()): print self.info("onBars().closePosition(), instrument:%s" % (instrument)) self.info( "onBars().closePosition(), LONG POSITION to close %.2f" % (self.longPosition[instrument].getShares())) self.longPosition[instrument].exitMarket() if (self.shortPosition[instrument] is not None and self.buySignal[instrument] == True and not self.shortPosition[instrument].exitActive()): print self.info("onBars().closePosition(), instrument:%s" % (instrument)) self.info( "onBars().closePosition(), SHORT POSITION to close %.2f" % (self.shortPosition[instrument].getShares())) self.shortPosition[instrument].exitMarket() def openPosition(self): '''mid 此处是onBars,这个和zipline的概念完全不同 zipline中,需要覆写的是handle_data,这个东西是个tick概念,所以没有OHLC的,只是个price PAT中,每次onBars,都会传入一个newbar的OHLC,此时,要如何按这个OHLC决策,全由你 依据OHLC做完决策后,可以发送交易指令: * Order.Type.MARKET * Order.Type.LIMIT * Order.Type.STOP * Order.Type.STOP_LIMIT 1.市价单,依据下一个bar的openPrice执行命令: self.enterLong() 2.限价单 3.止损单市价单 4.止损限价单 当前似乎没有止盈单 在均线策略中,应该在每个newbar到来时,按closePrice的均线计算指标值,然后发送市价单 1.每个newbar按close价格计算指标,并在下一个bar按open成交 2.每个newbar按open价格计算指标,并在此newbar按open成交 以上1,2的计算逻辑是一致的。如果当前bar的close和下一个bar的open相差无几时,两种算法的回测结果也应相差无几 ''' # mid 2)open if (self.shortAllowed): for instrument in self.instruments: self.curInstrument = instrument if (self.sellSignal[instrument] == True): # Enter a buy market order. The order is good till canceled. bar = self.getFeed().getLastBar(instrument) volume = 0 lastClose = 0 if bar is not None: volume = bar.getVolume() lastClose = bar.getClose() shares = self.money.getShares(strat=self) print self.info("onBars().openPosition(), instrument %s" % (instrument)) self.info( "onBars().openPosition(), SHORT POSITION to open %.2f" % (shares)) self.info("onBars().openPosition(), lastClose: %.2f,%.2f" % (self.getLastPrice(instrument), lastClose)) self.info("onBars().openPosition(), need amount: %.2f" % (shares * self.getLastPrice(instrument))) self.info( "onBars().openPosition(), available amount: %.2f." % (self.getBroker().getCash())) self.info( "onBars().openPosition(), available volume: %.2f." % (volume)) self.shortPosition[instrument] = self.enterShort( instrument, shares, True) if (self.longAllowed): for instrument in self.instruments: self.curInstrument = instrument if (self.buySignal[instrument] == True): shares = self.money.getShares(strat=self) print self.info("onBars().openPosition(), instrument %s" % (instrument)) self.info( "onBars().openPosition(), LONG POSITION to open %.2f" % (shares)) self.info("onBars().openPosition(), need amount: %.2f." % (shares * self.getLastPrice(instrument))) self.info( "onBars().openPosition(), available amount: %.2f." % (self.getBroker().getCash())) self.longPosition[instrument] = self.enterLong( instrument, shares, True) def __analiseEachSymbol(self, instrument): dataForCandle = self.dataCenter.getCandleData( dataProvider=self.dataProvider, dataStorage=self.storageType, dataPeriod=self.period, symbol=instrument, dateStart=self.timeFrom, dateEnd=self.timeTo) self.analyzer.analyseEachSymbol(self.results[instrument], dataForCandle, InKLine=self.InKLine) def __analiseSummary(self): dataProvider = self.benchDataProvider instrument = self.benchSymbol dataForCandle = self.dataCenter.getCandleData( dataProvider=dataProvider, dataStorage=self.storageType, dataPeriod=self.period, symbol=instrument, dateStart=self.timeFrom, dateEnd=self.timeTo) self.analyzer.analyseSummary(self.result, dataForCandle) def run(self, timeFrom=None, timeTo=None): self.initEa(timeFrom=timeFrom, timeTo=timeTo) self.initIndicators() #self.strat.setUseAdjustedValues(False) self.initAnalyzer() strategy.BacktestingStrategy.run(self) for instrument in self.instruments: buy = self.getBuy(instrument) sell = self.getSell(instrument) position_value = self.getPositionValue(instrument) long_volume = self.getLongVolume(instrument) short_volume = self.getShortVolume(instrument) long_cost = self.getLongCost(instrument) long_pnl = self.getLongPnl(instrument) short_cost = self.getShortCost(instrument) short_pnl = self.getShortPnl(instrument) self.results[instrument] = pd.DataFrame( { 'long_volume': list(long_volume), 'long_cost': list(long_cost), 'long_pnl': list(long_pnl), 'short_cost': list(short_cost), 'short_pnl': list(short_pnl), 'buy': list(buy), 'sell': list(sell), 'position_value': list(position_value) }, columns=[ 'long_volume', 'long_cost', 'long_pnl', 'short_cost', 'short_pnl', 'buy', 'sell', 'position_value' ], index=long_volume.getDateTimes()) self.addIndicators(instrument) #------------------------------------ if (self.toPlotEachSymbol): self.__analiseEachSymbol(instrument) if (self.toPlotSummary): portfolio_value = self.getPortfolioValue() available_cash = self.getAvailableCash() self.result = pd.DataFrame( { 'available_cash': list(available_cash), 'portfolio_value': list(portfolio_value) }, columns=['available_cash', 'portfolio_value'], index=portfolio_value.getDateTimes()) self.__analiseSummary() return self.results #mid from ea #---------------------------------------------------------------------- def summary(self): return "from %s to %s:returns:%.2f%%,sharpe:%.2f,MaxDrawdown:%.2f%%,Longest drawdown duration:(%s)" % ( str(self.timeFrom), str(self.timeTo), self.returnsAnalyzer.getCumulativeReturns()[-1] * 100, self.sharpeRatioAnalyzer.getSharpeRatio(0.05), self.drawdownAnalyzer.getMaxDrawDown() * 100, self.drawdownAnalyzer.getLongestDrawDownDuration()) def detail(self): """""" print "-------------------------------------------------------------------------" print "Final portfolio value: $%.2f" % self.getResult() print "Cumulative returns: %.2f %%" % ( self.returnsAnalyzer.getCumulativeReturns()[-1] * 100) print "Sharpe ratio: %.2f" % ( self.sharpeRatioAnalyzer.getSharpeRatio(0.05)) print "Max. drawdown: %.2f %%" % ( self.drawdownAnalyzer.getMaxDrawDown() * 100) print "Longest drawdown duration: (%s)" % ( self.drawdownAnalyzer.getLongestDrawDownDuration()) print print "Total trades: %d" % (self.tradesAnalyzer.getCount()) if self.tradesAnalyzer.getCount() > 0: profits = self.tradesAnalyzer.getAll() print "Avg. profit: $%2.f" % (profits.mean()) print "Profits std. dev.: $%2.f" % (profits.std()) print "Max. profit: $%2.f" % (profits.max()) print "Min. profit: $%2.f" % (profits.min()) returns = self.tradesAnalyzer.getAllReturns() print "Avg. return: %2.f %%" % (returns.mean() * 100) print "Returns std. dev.: %2.f %%" % (returns.std() * 100) print "Max. return: %2.f %%" % (returns.max() * 100) print "Min. return: %2.f %%" % (returns.min() * 100) print print "Profitable trades: %d" % ( self.tradesAnalyzer.getProfitableCount()) if self.tradesAnalyzer.getProfitableCount() > 0: profits = self.tradesAnalyzer.getProfits() print "Avg. profit: $%2.f" % (profits.mean()) print "Profits std. dev.: $%2.f" % (profits.std()) print "Max. profit: $%2.f" % (profits.max()) print "Min. profit: $%2.f" % (profits.min()) returns = self.tradesAnalyzer.getPositiveReturns() print "Avg. return: %2.f %%" % (returns.mean() * 100) print "Returns std. dev.: %2.f %%" % (returns.std() * 100) print "Max. return: %2.f %%" % (returns.max() * 100) print "Min. return: %2.f %%" % (returns.min() * 100) print print "Unprofitable trades: %d" % ( self.tradesAnalyzer.getUnprofitableCount()) if self.tradesAnalyzer.getUnprofitableCount() > 0: losses = self.tradesAnalyzer.getLosses() print "Avg. loss: $%2.f" % (losses.mean()) print "Losses std. dev.: $%2.f" % (losses.std()) print "Max. loss: $%2.f" % (losses.min()) print "Min. loss: $%2.f" % (losses.max()) returns = self.tradesAnalyzer.getNegativeReturns() print "Avg. return: %2.f %%" % (returns.mean() * 100) print "Returns std. dev.: %2.f %%" % (returns.std() * 100) print "Max. return: %2.f %%" % (returns.max() * 100) print "Min. return: %2.f %%" % (returns.min() * 100) print "-------------------------------------------------------------------------" def initAnalyzer(self): from pyalgotrade.stratanalyzer import sharpe from pyalgotrade.stratanalyzer import returns from pyalgotrade.stratanalyzer import drawdown from pyalgotrade.stratanalyzer import trades # 1.0) 策略结果 self.returnsAnalyzer = returns.Returns() # 1.1) 夏普比率 self.sharpeRatioAnalyzer = sharpe.SharpeRatio() # 1.2) self.drawdownAnalyzer = drawdown.DrawDown() # 1.3) self.tradesAnalyzer = trades.Trades() self.attachAnalyzer(self.sharpeRatioAnalyzer) self.attachAnalyzer(self.returnsAnalyzer) self.attachAnalyzer(self.tradesAnalyzer) self.attachAnalyzer(self.drawdownAnalyzer)
class DMACrossOver(strategy.BacktestingStrategy): def __init__(self, feed=None, instrument='', shortPeriod=0, longPeriod=0, money=None, longAllowed=True, shortAllowed=True): strategy.BacktestingStrategy.__init__(self, feed) self.position_cost = 0 #mid init position value mid_DEFAULT_MAX_LEN = 10 * DEFAULT_MAX_LEN self.__instrument = instrument self.__longPosition = None self.__shortPosition = None self.__position_volume = SequenceDataSeries( maxLen=mid_DEFAULT_MAX_LEN) #mid 当前持有头寸数量 self.__position_cost = SequenceDataSeries( maxLen=mid_DEFAULT_MAX_LEN) #mid 当前持有头寸开仓成本 self.__position_pnl = SequenceDataSeries( maxLen=mid_DEFAULT_MAX_LEN) #mid 当前持有头寸价值 self.__portfolio_value = SequenceDataSeries(maxLen=mid_DEFAULT_MAX_LEN) self.__buy = SequenceDataSeries(maxLen=mid_DEFAULT_MAX_LEN) self.__sell = SequenceDataSeries(maxLen=mid_DEFAULT_MAX_LEN) self.__buySignal = False self.__sellSignal = False self.money = money self.longAllowed = True self.shortAllowed = True #mid 计算ma将使用当天的收盘价格计算 #mid 1) dataSeries = feed[instrument] dataSeries.setMaxLen(mid_DEFAULT_MAX_LEN) closeSeries = dataSeries.getOpenDataSeries() #mid 2) prices = closeSeries prices.setMaxLen(mid_DEFAULT_MAX_LEN) #mid 3) self.__sma = ma.SMA(prices, shortPeriod, maxLen=mid_DEFAULT_MAX_LEN) self.__lma = ma.SMA(prices, longPeriod, maxLen=mid_DEFAULT_MAX_LEN) self.i = 0 def getAssetStructure(self): #mid -------------------------------- #mid 当前账户资产结构如下方式获取 #mid Long 和 Short不会同时存在 #mid 在开仓前,若有反向持仓,则此过程查询并输出已持有的反向持仓 broker = self.getBroker() portfolio_value = broker.getEquity() cash = broker.getCash() if self.__shortPosition is not None or self.__longPosition is not None: bars = self.getFeed().getCurrentBars() positions = broker.getPositions() positionsOpenValue = {} positionsCloseValue = {} for key, value in positions.items(): print "key:" + key + ",value:" + str(value) bar = bars.getBar(key) openPrice = bar.getOpen() closePrice = bar.getClose() share = broker.getShares(key) positionsOpenValue[key] = openPrice * share positionsCloseValue[key] = closePrice * share print print 'current bar asset structure' print 'open cash %2.f.' % (cash) for key, value in positionsOpenValue.items(): print "key:" + key + ",value:" + str(value) print 'close cash %2.f.' % (cash) for key, value in positionsCloseValue.items(): print "key:" + key + ",value:" + str(value) print 'portfolio:%2.f' % (portfolio_value) return portfolio_value, cash, sum(positionsCloseValue.values()) return portfolio_value, cash, 0 def recordPositions(self): # record position ####################################################################### broker = self.getBroker() position = broker.getPositions() #mid position is dict of share share = broker.getShares( self.__instrument) #mid position is dict of share lastPrice = self.getLastPrice(self.__instrument) portfolio_value = broker.getEquity() #mid 按close价格计算的权益 cash = broker.getCash() position_value = portfolio_value - cash position_pnl = position_value - self.position_cost print print 'cash: %.2f' % (cash) print 'position value: %.2f' % (portfolio_value - cash) print 'mid calc: %.2f' % (lastPrice * share + cash) print 'broker returned: %.2f' % (portfolio_value) curTime = self.getCurrentDateTime() if (False): yLimit = self.money.getShares() * 1.1 if (self.i == 0): self.__position.append(yLimit) self.i = self.i + 1 elif (self.i == 1): self.__position.append(-yLimit) self.i = self.i + 1 else: currentTime = self.getCurrentDateTime() self.__position.appendWithDateTime(currentTime, abs(share)) #self.__position.append(share) else: currentTime = self.getCurrentDateTime() self.__position_volume.appendWithDateTime(currentTime, abs(share)) self.__position_cost.appendWithDateTime(currentTime, abs(self.position_cost)) self.__position_pnl.appendWithDateTime(currentTime, position_pnl) self.__portfolio_value.appendWithDateTime(currentTime, portfolio_value) self.__buy.appendWithDateTime(currentTime, self.__buySignal) self.__sell.appendWithDateTime(currentTime, self.__sellSignal) def getInstrument(self): return self.__instrument def getPortfolio(self): return self.__portfolio_value def getPositionVolume(self): return self.__position_volume def getPositionCost(self): return self.__position_cost def getPositionPnl(self): return self.__position_pnl def getSMA(self): return self.__sma def getLMA(self): return self.__lma def getBuy(self): return self.__buy def getSell(self): return self.__sell def onEnterOk(self, position): execInfo = position.getEntryOrder().getExecutionInfo() portfolio = self.getResult() cash = self.getBroker().getCash() '''mid 以下两种方法都是为了计算持仓成本 由于getEquity()返回的是依据当日close价格计算出来的权益 所以,这个值不能作为持仓成本 持仓成本需要以onEnterOk时bar的open价格计算 所以应使用第二种算法 由于经常有跳开现象,所以依据bar(n-1).close发出的market order, 在bar(n).open执行时通常会有gap出现,表现在position_cost图上时就是持有成本离计划成本会有跳口, ''' if (False): #mid two methods to cacl cost. portfolio_value = self.getBroker().getEquity() self.position_cost = portfolio_value - cash else: feed = self.getFeed() bars = feed.getCurrentBars() bar = bars.getBar(self.__instrument) openPrice = bar.getOpen() closePrice = self.getLastPrice( self.__instrument) #mid lastPrice == closePrice share = self.getBroker().getShares(self.__instrument) self.position_cost = openPrice * share self.info("onEnterOk().current available cash: %.2f,portfolio: %.2f." % (cash, portfolio)) if isinstance(position, strategy.position.LongPosition): self.info("onEnterOK().ExecutionInfo: %s,OPEN LONG %.2f at $%.2f" % (execInfo.getDateTime(), execInfo.getQuantity(), execInfo.getPrice())) elif isinstance(position, strategy.position.ShortPosition): self.info( "onEnterOK().ExecutionInfo: %s,OPEN SHORT %.2f at $%.2f" % (execInfo.getDateTime(), execInfo.getQuantity(), execInfo.getPrice())) def onEnterCanceled(self, position): self.info("onEnterCanceled().current available cash: %.2f." % (self.getBroker().getCash())) if isinstance(position, strategy.position.LongPosition): self.__longPosition = None self.info("onEnterCanceled().OPEN LONG cancled.") elif isinstance(position, strategy.position.ShortPosition): self.__shortPosition = None self.info("onEnterCanceled().OPEN SHORT cancled.") def onExitOk(self, position): execInfo = position.getExitOrder().getExecutionInfo() portfolio = self.getResult() cash = self.getBroker().getCash() self.info("onExitOk().current available cash: %.2f,portfolio: %.2f." % (cash, portfolio)) if isinstance(position, strategy.position.LongPosition): self.__longPosition = None self.info("onExitOk().ExecutionInfo: %s,CLOSE LONG %.2f at $%.2f" % (execInfo.getDateTime(), execInfo.getQuantity(), execInfo.getPrice())) elif isinstance(position, strategy.position.ShortPosition): self.__shortPosition = None self.info( "onExitOk().ExecutionInfo: %s,CLOSE SHORT %.2f at $%.2f" % (execInfo.getDateTime(), execInfo.getQuantity(), execInfo.getPrice())) def onExitCanceled(self, position): # If the exit was canceled, re-submit it. if isinstance(position, strategy.position.LongPosition): self.__longPosition = None elif isinstance(position, strategy.position.ShortPosition): self.__shortPosition = None def logInfo(self, bars=None): pLong, pShort = 0, 0 if (self.__longPosition is not None): pLong = self.__longPosition.getShares() if (self.__shortPosition is not None): pShort = self.__shortPosition.getShares() bar = bars[self.__instrument] pOpen = bar.getOpen() pHigh = bar.getHigh() pLow = bar.getLow() pClose = bar.getClose() pPrice = bar.getPrice() self.info( 'logInfo().price:%.3f,open:%.2f,high:%.2f,low:%.2f,close:%.2f' % (pPrice, pOpen, pHigh, pLow, pClose)) #self.info('long:%.2f#short:%.2f'%(pLong,pShort)) def run(self): strategy.BacktestingStrategy.run(self) sma = self.getSMA() lma = self.getLMA() buy = self.getBuy() sell = self.getSell() portfolio_value = self.getPortfolio() position_volume = self.getPositionVolume() position_cost = self.getPositionCost() position_pnl = self.getPositionPnl() result = pd.DataFrame( { 'position_volume': list(position_volume), 'position_cost': list(position_cost), 'position_pnl': list(position_pnl), 'short_ema': list(sma), 'long_ema': list(lma), 'buy': list(buy), 'sell': list(sell), 'portfolio_value': list(portfolio_value) }, columns=[ 'position_volume', 'position_cost', 'position_pnl', 'short_ema', 'long_ema', 'buy', 'sell', 'portfolio_value' ], index=position_volume.getDateTimes()) return result def onBars(self, bars): '''mid 此处是onBars,这个和zipline的概念完全不同 zipline中,需要覆写的是handle_data,这个东西是个tick概念,所以没有OHLC的,只是个price PAT中,每次onBars,都会传入一个newbar的OHLC,此时,要如何按这个OHLC决策,全由你 依据OHLC做完决策后,可以发送交易指令: * Order.Type.MARKET * Order.Type.LIMIT * Order.Type.STOP * Order.Type.STOP_LIMIT 1.市价单,依据下一个bar的openPrice执行命令: self.enterLong() 2.限价单 3.止损单市价单 4.止损限价单 当前似乎没有止盈单 在均线策略中,应该在每个newbar到来时,按closePrice的均线计算指标值,然后发送市价单 1.每个newbar按close价格计算指标,并在下一个bar按open成交 2.每个newbar按open价格计算指标,并在此newbar按open成交 以上1,2的计算逻辑是一致的。如果当前bar的close和下一个bar的open相差无几时,两种算法的回测结果也应相差无几 ''' self.__buySignal, self.__sellSignal = False, False # mid 1)close if (self.longAllowed): if self.__longPosition is not None and not self.__longPosition.exitActive( ): #mid 有多仓,检查是否需要平仓 if (cross.cross_below(self.__sma, self.__lma) > 0): print self.info( "onBars().Status info,before exitMarket(), LONG POSITION to close %.2f" % (self.__longPosition.getShares())) self.__longPosition.exitMarket() if (self.shortAllowed): if self.__shortPosition is not None and not self.__shortPosition.exitActive( ): if (cross.cross_above(self.__sma, self.__lma) > 0): print self.info( "onBars().Status info,before exitMarket(), SHORT POSITION to close %.2f" % (self.__shortPosition.getShares())) self.__shortPosition.exitMarket() # mid 2)open if (self.longAllowed): if self.__longPosition is None: #mid 无多仓,检查是否需要开多仓 if cross.cross_above(self.__sma, self.__lma) > 0: # Enter a buy market order. The order is good till canceled. shares = self.money.getShares(strat=self) self.info( "onBars().Status info,before enterLong(), LONG POSITION to open %.2f,need amount: %.2f,available amount: %.2f." % (shares, shares * self.getLastPrice(self.__instrument), self.getBroker().getCash())) self.__longPosition = self.enterLong( self.__instrument, shares, True) self.__buySignal = True if (self.shortAllowed): if self.__shortPosition is None: if cross.cross_below(self.__sma, self.__lma) > 0: # Enter a buy market order. The order is good till canceled. shares = self.money.getShares(strat=self) self.info( "onBars().Status info,before enterShort(), SHORT POSITION to open %.2f,need amount: %.2f,available amount: %.2f." % (shares, shares * self.getLastPrice(self.__instrument), self.getBroker().getCash())) self.__shortPosition = self.enterShort( self.__instrument, shares, True) self.__sellSignal = True self.recordPositions()
def adjustBars(self): for key, value in self.__barsDict.iteritems(): basicbars = [] bars = value bars_in_dtrange = [bar for bar in bars if self.__startdate.replace(tzinfo=None) <= bar.getDateTime() <= self.__enddate.replace(tzinfo=None)] bars_in_dtrange.sort(key=lambda bar: bar.getDateTime(), reverse=True) k = 0 splitdataList = [] dividendList = [] for bar in bars_in_dtrange: splitdata = float(bar.getSplit()) dividend = float(bar.getDividend()) if splitdata != 1.0: splitdataList.append(bar.getSplit()) if dividend != 0.0: adjFactor = (bar.getClose() + bar.getDividend()) / bar.getClose() dividendList.append(adjFactor) #### Special case.... end date / analysis date nothing to do.. if (k==0): bar = BasicBar(bar.getDateTime(), bar.getOpen() , bar.getHigh(), bar.getLow(), bar.getClose(), bar.getVolume(), bar.getClose(), Frequency.DAY) basicbars.append(bar) else: #### Adjust OHLC & Volume data for split adjustments and dividend adjustments Open = bar.getOpen() High = bar.getHigh() Low = bar.getLow() Close = bar.getClose() Volume = bar.getVolume() ### adjust data for splits for split in splitdataList: Open = Open / split High = High / split Low = Low / split Close = Close /split Volume = Volume * split ### adjust data for dividends for adjFactor in dividendList: Open = Open / adjFactor High = High / adjFactor Low = Low / adjFactor Close = Close / adjFactor Volume = Volume * adjFactor bar = BasicBar(bar.getDateTime(), Open , High, Low, Close, Volume, Close, Frequency.DAY) basicbars.append(bar) k +=1 DateTimes = [] OpenSeries = SequenceDataSeries(4000) HighSeries = SequenceDataSeries(4000) LowSeries = SequenceDataSeries(4000) CloseSeries = SequenceDataSeries(4000) VolumeSeries = SequenceDataSeries(4000) TypicalSeries = SequenceDataSeries(4000) barSeries = BarDataSeries(4000) basicbars.sort(key=lambda bar: bar.getDateTime(), reverse=False) for bar in basicbars: DateTimes.append(bar.getDateTime()) OpenSeries.appendWithDateTime(bar.getDateTime(), bar.getOpen()) HighSeries.appendWithDateTime(bar.getDateTime(), bar.getHigh()) LowSeries.appendWithDateTime(bar.getDateTime(), bar.getLow()) CloseSeries.appendWithDateTime(bar.getDateTime(), bar.getClose()) VolumeSeries.appendWithDateTime(bar.getDateTime(), bar.getVolume()) TypicalSeries.appendWithDateTime(bar.getDateTime(), (bar.getClose()+bar.getHigh()+bar.getLow())/3.0) barSeries.appendWithDateTime(bar.getDateTime(), bar) self.__DateTimes[key+"_adjusted"] = DateTimes self.__OpenDataSeries[key+"_adjusted"] = OpenSeries self.__HighDataSeries[key+"_adjusted"] = HighSeries self.__LowDataSeries[key+"_adjusted"] = LowSeries self.__CloseDataSeries[key+"_adjusted"] = CloseSeries self.__VolumeDataSeries[key+"_adjusted"] = VolumeSeries self.__TypicalDataSeries[key+"_adjusted"] = TypicalSeries self.__barSeries[key+"_adjusted"] = barSeries