def runMod(mod, joinedData): pred = dataAck.computePosition([ mod.makeTodayPrediction( portfolio.prepareDataForModel(mod, joinedData)) ]) print(mod.describe(), pred, joinedData.index[-1]) portfolio.storeModelPrediction(mod, pred, joinedData.index[-1]) ##ENSURE POPULATED FOR CORRECT PREDICTION STYLE i = mod.inputSeries.predictionPeriod - 1 while i > 0: pred = dataAck.computePosition( [mod.makeTodayPrediction(joinedData[:-i])]) print(mod.describe(), pred, joinedData[:-i].index[-1]) portfolio.storeModelPrediction(mod, pred, joinedData[:-i].index[-1]) i -= 1
def runBackfillMP(mod, joinedData, threadsToUse, backfillDays = 30): mpEngine = mp.get_context('fork') i = mod.inputSeries.predictionPeriod - 1 + backfillDays runningP = [] while i > 0: while len(runningP) > threadsToUse: runningP = dataAck.cycleP(runningP) p = mpEngine.Process(target=runModPredictionBackfill, args=(mod, joinedData[:-i], backfillDays, )) p.start() runningP.append(p) i -= 1 while len(runningP) > 0: runningP = dataAck.cycleP(runningP) print("CHECKING AGGREGATE PREDICTIONS") ##STORE AGGREGATE PREDICTIONS i = mod.inputSeries.predictionPeriod - 1 + backfillDays allPreds = portfolio.getPredictionsByModel(mod) while i > 0: lastDay = joinedData[:-i].index[-1] todayPredictions = [] for pred in allPreds: ##CHECK IF PREDICTION STILL VALID if len(joinedData[str(pred["lastDataDayUsed"]):lastDay]) - 1 < pred["predictionLength"] and len(joinedData[str(pred["lastDataDayUsed"]):lastDay]) > 0:##GETS TRADING DAYS SINCE LAST DATA DAY todayPredictions.append(pred["prediction"]) ##SKIP UPLOAD IF NOT ENOUGH PREDICTIONS print(lastDay, len(todayPredictions)) if len(todayPredictions) == mod.inputSeries.predictionPeriod: pred = dataAck.computePosition(todayPredictions) print(mod.describe(), todayPredictions, pred) portfolio.storeAggregateModelPrediction(mod, pred, lastDay) i -= 1
def getAggregatePredictionForModelDaily(model, joinedData): todayPredictions = [] for pred in getPredictionsByModel(model): ##CHECK IF PREDICTION STILL VALID if len(joinedData[str(pred["lastDataDayUsed"]):]) - 1 < pred[ "predictionLength"]: ##GETS TRADING DAYS SINCE LAST DATA DAY todayPredictions.append(pred["prediction"]) #print(model.describe(), todayPredictions, dataAck.computePosition(todayPredictions)) return dataAck.computePosition(todayPredictions)
def generateRawPredictions(allModels, joinedData, daysBack=False): for mod in allModels: pred = dataAck.computePosition([ mod.makeTodayPrediction( portfolio.prepareDataForModel(mod, joinedData)) ]) print(mod.describe(), pred, joinedData.index[-1]) portfolio.storeModelPrediction(mod, pred, joinedData.index[-1]) if daysBack == True: ##ENSURE POPULATED FOR CORRECT PREDICTION STYLE i = mod.inputSeries.predictionPeriod - 1 while i > 0: pred = dataAck.computePosition( [mod.makeTodayPrediction(joinedData[:-i])]) print(mod.describe(), pred, joinedData[:-i].index[-1]) portfolio.storeModelPrediction(mod, pred, joinedData[:-i].index[-1]) i -= 1
def runModelToday(self, dataOfInterest): xVals, yVals, yIndex, xToday = self.generateWindows(dataOfInterest) ##GET PERTINENT PREDICTIONS i = 0 predictionsToJoin = [] while i < self.predictionDistance: xTarget = xVals[-i] thisDayPrediction = self.runDay(xVals[:-i - 1], yVals[:-i - 1], xTarget, identifier=None, sharedDict=None) predictionsToJoin.append(thisDayPrediction) i += 1 print("PREDICTIONS TO JOIN", predictionsToJoin) return dataAck.computePosition(predictionsToJoin)
def runModPredictionBackfill(mod, dataToUse, backfillDays = 30): ##ENSURE POPULATED FOR CORRECT PREDICTION STYLE pred = dataAck.computePosition([mod.makeTodayPrediction(dataToUse)]) print(mod.describe(), pred, dataToUse.index[-1]) portfolio.storeModelPrediction(mod, pred, dataToUse.index[-1])
def runModelToday(self, dataOfInterest): return self.combinePredictions([ dataAck.computePosition([self.obj1.runModelToday(dataOfInterest)]), dataAck.computePosition([self.obj2.runModelToday(dataOfInterest)]) ])
def runModelHistorical(self, dataOfInterest): ##RAW PREDICTIONS ARE PREDS 0->1.0 returnStream, factorReturn, predictions, slippageAdjustedReturn, rawPredictions1 = self.obj1.runModelHistorical( dataOfInterest) returnStream, factorReturn, predictions, slippageAdjustedReturn, rawPredictions2 = self.obj2.runModelHistorical( dataOfInterest) print(rawPredictions1) print(rawPredictions2) #computePositionConfidence rawPredictions1 = pd.DataFrame(rawPredictions1.apply( lambda x: dataAck.computePosition(x), axis=1), columns=["Predictions 1"]).dropna() rawPredictions2 = pd.DataFrame(rawPredictions2.apply( lambda x: dataAck.computePosition(x), axis=1), columns=["Predictions 2"]).dropna() print(rawPredictions1) print(rawPredictions2) rawPredictions = rawPredictions1.join(rawPredictions2).dropna() print(rawPredictions) #averagePredictions predsTable = pd.DataFrame( rawPredictions.apply(lambda x: self.combinePredictions(x), axis=1, raw=True)) rawPredictions = predsTable ##PREDICTIONS COMBINED AS 0, 0.5, 1 where i = 1 tablesToJoin = [] while i < self.predictionDistance: thisTable = predsTable.shift(i) thisTable.columns = ["Predictions_" + str(i)] tablesToJoin.append(thisTable) i += 1 returnStream = None factorReturn = None predictions = None slippageAdjustedReturn = None predsTable = predsTable.join(tablesToJoin) ##AVERAGE...A LOT OF SUBTLETY IN STRENGTH OF PREDICTION transformedPreds = pd.DataFrame(predsTable.apply( lambda x: dataAck.computePosition(x), axis=1), columns=["Predictions"]).dropna() dailyFactorReturn = dataAck.getDailyFactorReturn( self.targetTicker, dataOfInterest) transformedPreds = transformedPreds.join(dailyFactorReturn).dropna() returnStream = pd.DataFrame(transformedPreds.apply( lambda x: x[0] * x[1], axis=1), columns=["Algo Return"]) factorReturn = pd.DataFrame(transformedPreds[["Factor Return"]]) predictions = pd.DataFrame(transformedPreds[["Predictions"]]) estimatedSlippageLoss = portfolioGeneration.estimateTransactionCost( predictions) estimatedSlippageLoss.columns = returnStream.columns slippageAdjustedReturn = (returnStream - estimatedSlippageLoss).dropna() return returnStream, factorReturn, predictions, slippageAdjustedReturn, rawPredictions
def runModelsChunksSkipMP(self, dataOfInterest, daysToCheck = None, earlyStop=False): xVals, yVals, yIndex, xToday = self.generateWindows(dataOfInterest) mpEngine = mp.get_context('fork') with mpEngine.Manager() as manager: returnDict = manager.dict() identifiersToCheck = [] for i in range(len(xVals) - 44): ##44 is lag...should not overlap with any other predictions or will ruin validity of walkforward optimization if i < 600: ##MIN TRAINING continue identifiersToCheck.append(str(i)) if daysToCheck is not None: identifiersToCheck = identifiersToCheck[-daysToCheck:] ##FIRST CHECK FIRST 500 IDENTIFIERS AND THEN IF GOOD CONTINUE identifierWindows = [identifiersToCheck[:252], identifiersToCheck[252:600], identifiersToCheck[600:900], identifiersToCheck[900:1200], identifiersToCheck[1200:]] ##EXACTLY TWO YEARS if earlyStop == False: identifierWindows = [identifiersToCheck] returnStream = None factorReturn = None predictions = None slippageAdjustedReturn = None rawPredictions = None shortSeen = 0 if earlyStop == True else -1 for clippedIdentifiers in identifierWindows: splitIdentifiers = np.array_split(np.array(clippedIdentifiers), 4) runningP = [] k = 0 for identifiers in splitIdentifiers: p = mpEngine.Process(target=CurvePredictor.runDayChunking, args=(self, xVals, yVals, identifiers, returnDict,k)) p.start() runningP.append(p) k += 1 while len(runningP) > 0: newP = [] for p in runningP: if p.is_alive() == True: newP.append(p) else: p.join() runningP = newP preds = [] actuals = [] days = [] for i in clippedIdentifiers: preds.append(returnDict[i]) actuals.append(yVals[int(i) + 44]) days.append(yIndex[int(i) + 44]) ##CREATE ACCURATE BLENDING ACROSS DAYS predsTable = pd.DataFrame(preds, index=days, columns=["Predictions"]) i = 1 tablesToJoin = [] while i < self.predictionDistance: thisTable = predsTable.shift(i) thisTable.columns = ["Predictions_" + str(i)] tablesToJoin.append(thisTable) i += 1 predsTable = predsTable.join(tablesToJoin) transformedPreds = pd.DataFrame(predsTable.apply(lambda x:dataAck.computePosition(x), axis=1), columns=["Predictions"]).dropna() dailyFactorReturn = dataAck.getDailyFactorReturn(self.targetTicker, dataOfInterest) transformedPreds = transformedPreds.join(dailyFactorReturn).dropna() returnStream = pd.DataFrame(transformedPreds.apply(lambda x:x[0] * x[1], axis=1), columns=["Algo Return"]) if returnStream is None else pd.concat([returnStream, pd.DataFrame(transformedPreds.apply(lambda x:x[0] * x[1], axis=1), columns=["Algo Return"])]) factorReturn = pd.DataFrame(transformedPreds[["Factor Return"]]) if factorReturn is None else pd.concat([factorReturn, pd.DataFrame(transformedPreds[["Factor Return"]])]) predictions = pd.DataFrame(transformedPreds[["Predictions"]]) if predictions is None else pd.concat([predictions, pd.DataFrame(transformedPreds[["Predictions"]])]) rawPredictions = pd.DataFrame(preds, index=days, columns=["Predictions"]) if rawPredictions is None else pd.concat([rawPredictions, pd.DataFrame(preds, index=days, columns=["Predictions"])]) alpha, beta = empyrical.alpha_beta(returnStream, factorReturn) activity = np.count_nonzero(returnStream)/float(len(returnStream)) rawBeta = abs(empyrical.alpha_beta(returnStream.apply(lambda x:dataAck.applyBinary(x), axis=0), factorReturn.apply(lambda x:dataAck.applyBinary(x), axis=0))[1]) shortSharpe = empyrical.sharpe_ratio(returnStream) activity = np.count_nonzero(returnStream)/float(len(returnStream)) algoAnnualReturn = empyrical.annual_return(returnStream.values)[0] algoVol = empyrical.annual_volatility(returnStream.values) factorAnnualReturn = empyrical.annual_return(factorReturn.values)[0] factorVol = empyrical.annual_volatility(factorReturn.values) treynor = ((empyrical.annual_return(returnStream.values)[0] - empyrical.annual_return(factorReturn.values)[0]) \ / abs(empyrical.beta(returnStream, factorReturn))) sharpeDiff = empyrical.sharpe_ratio(returnStream) - empyrical.sharpe_ratio(factorReturn) relativeSharpe = sharpeDiff / empyrical.sharpe_ratio(factorReturn) * (empyrical.sharpe_ratio(factorReturn)/abs(empyrical.sharpe_ratio(factorReturn))) stability = empyrical.stability_of_timeseries(returnStream) ##CALCULATE SHARPE WITH SLIPPAGE estimatedSlippageLoss = portfolioGeneration.estimateTransactionCost(predictions) estimatedSlippageLoss.columns = returnStream.columns slippageAdjustedReturn = (returnStream - estimatedSlippageLoss).dropna() slippageSharpe = empyrical.sharpe_ratio(slippageAdjustedReturn) sharpeDiffSlippage = empyrical.sharpe_ratio(slippageAdjustedReturn) - empyrical.sharpe_ratio(factorReturn) relativeSharpeSlippage = sharpeDiffSlippage / empyrical.sharpe_ratio(factorReturn) * (empyrical.sharpe_ratio(factorReturn)/abs(empyrical.sharpe_ratio(factorReturn))) profitability = len((returnStream.values)[returnStream.values > 0])/len(returnStream.values) rollingProfitability = returnStream.rolling(45, min_periods=45).apply(lambda x:len((x)[x > 0])/len(x)).dropna().values minRollingProfitability = np.percentile(rollingProfitability, 1) twentyFifthPercentileRollingProfitablity = np.percentile(rollingProfitability, 25) if np.isnan(shortSharpe) == True: return None, {"sharpe":shortSharpe}, None, None, None elif (profitability < 0.4 or activity < 0.3 or abs(rawBeta) > 0.4 or stability < 0.3) and shortSeen == 0: return None, { "sharpe":shortSharpe, ##OVERLOADED IN FAIL "activity":activity, "factorSharpe":empyrical.sharpe_ratio(factorReturn), "sharpeSlippage":slippageSharpe, "beta":abs(beta), "alpha":alpha, "activity":activity, "treynor":treynor, "period":"first 252 days", "algoReturn":algoAnnualReturn, "algoVol":algoVol, "factorReturn":factorAnnualReturn, "factorVol":factorVol, "sharpeDiff":sharpeDiff, "relativeSharpe":relativeSharpe, "sharpeDiffSlippage":sharpeDiffSlippage, "relativeSharpeSlippage":relativeSharpeSlippage, "rawBeta":rawBeta, "minRollingProfitability":minRollingProfitability, "stability":stability, "twentyFifthPercentileRollingProfitablity":twentyFifthPercentileRollingProfitablity, "profitability":profitability }, None, None, None elif abs(rawBeta) > 0.33 or activity < 0.3 or stability < 0.4 or twentyFifthPercentileRollingProfitablity < 0.41 \ or minRollingProfitability < 0.3 or profitability < 0.46: periodName = "first 600 days" if shortSeen == 2: periodName = "first 900 days" elif shortSeen == 3: periodName = "first 1200 days" return None, { "sharpe":shortSharpe, ##OVERLOADED IN FAIL "activity":activity, "factorSharpe":empyrical.sharpe_ratio(factorReturn), "sharpeSlippage":slippageSharpe, "alpha":alpha, "beta":abs(beta), "activity":activity, "treynor":treynor, "period":periodName, "algoReturn":algoAnnualReturn, "algoVol":algoVol, "factorReturn":factorAnnualReturn, "factorVol":factorVol, "minRollingProfitability":minRollingProfitability, "sharpeDiff":sharpeDiff, "relativeSharpe":relativeSharpe, "sharpeDiffSlippage":sharpeDiffSlippage, "relativeSharpeSlippage":relativeSharpeSlippage, "rawBeta":rawBeta, "stability":stability, "twentyFifthPercentileRollingProfitablity":twentyFifthPercentileRollingProfitablity, "profitability":profitability }, None, None, None elif shortSeen < 4: print("CONTINUING", "SHARPE:", shortSharpe, "SHARPE DIFF:", sharpeDiff, "RAW BETA:", rawBeta, "TREYNOR:", treynor) shortSeen += 1 return returnStream, factorReturn, predictions, slippageAdjustedReturn, rawPredictions