def AlignPositions(tm:TradingModel, targetPositions:pd.DataFrame, stockCount:int, allocateByPointValue:bool= False, verbose:bool = False): #Helper function. Performs necessary Buy/Sells to get from current positions to target positions print(targetPositions) TotalTranches = tm._tranchCount targetPositions=pd.DataFrame(targetPositions.groupby(['Ticker','pointValue']).size()).reset_index() targetPositions.set_index(['Ticker'], inplace=True) targetPositions.rename(columns={0:'TargetHoldings'}, inplace=True) targetPositions.sort_values(by=['TargetHoldings', 'pointValue'], axis=0, ascending=False, inplace=True, kind='quicksort', na_position='last') targetPositions = targetPositions[:stockCount] print(targetPositions) if allocateByPointValue: TotalPoints = targetPositions['pointValue'].sum() scale = TotalTranches/TotalPoints print('scale', TotalPoints, TotalTranches, scale) targetPositions.loc[:, 'TargetHoldings'] = round(targetPositions.loc[:, 'TargetHoldings'] * targetPositions.loc[:, 'pointValue'] * scale) else: TotalTargets = targetPositions['TargetHoldings'].sum() scale = TotalTranches/TotalTargets print('scale', TotalTargets, TotalTranches, scale) targetPositions.loc[:, 'TargetHoldings'] = round(targetPositions.loc[:, 'TargetHoldings'] * scale) print(targetPositions) currentPositions = tm.GetPositions(asDataFrame=True) if len(currentPositions) > 0: #evaluate the difference between current holdings and target, act accordingly targetPositions = targetPositions.join(currentPositions, how='outer') targetPositions.fillna(value=0, inplace=True) targetPositions['Difference'] = targetPositions['TargetHoldings'] - targetPositions['CurrentHoldings'] print(targetPositions) for i in range(len(targetPositions)): sells = int(targetPositions.iloc[i]['Difference']) if sells < 0: t = targetPositions.index.values[i] print('Sell ' + str(abs(sells)) + ' ' + t) for _ in range(abs(sells)): tm.PlaceSell(ticker=t, price=1, marketOrder=True, expireAfterDays=10, verbose=verbose) tm.ProcessDay(withIncrement=False) for i in range(len(targetPositions)): buys = int(targetPositions.iloc[i]['Difference']) if buys > 0: t = targetPositions.index.values[i] print('Buy ' + str(buys) + ' ' + t) for _ in range(buys): tm.PlaceBuy(ticker=t, price=1, marketOrder=True, expireAfterDays=10, verbose=verbose) tm.ProcessDay(withIncrement=False) elif len(targetPositions) > 0: for i in range(len(targetPositions)): buys = int(targetPositions.iloc[i]['TargetHoldings']) if buys > 0: t = targetPositions.index.values[i] print(t) print(buys) print('Buy ' + str(buys) + ' ' + t) for _ in range(buys): tm.PlaceBuy(ticker=t, price=1, marketOrder=True, expireAfterDays=10, verbose=verbose) tm.ProcessDay(withIncrement=False) print(tm.GetPositions(asDataFrame=True)) print(tm.PositionSummary())
def RunTradingModelSeasonal(tm: TradingModel, ticker: str): SellMonth = 4 #April BuyMonth = 10 #October currentPrices = tm.GetPriceSnapshot() if not currentPrices == None: low = currentPrices.low high = currentPrices.high m = tm.currentDate.month available, buyPending, sellPending, longPositions = tm.PositionSummary( ) if m >= SellMonth and m <= BuyMonth: if longPositions > 0: tm.PlaceSell(ticker, high, True) else: if available > 0 and tm.FundsAvailable() > high: tm.PlaceBuy(ticker, low, True)
def RunTradingModelSeasonal(tm: TradingModel, ticker: str): #Buy in November, sell in May SellMonth = 5 BuyMonth = 11 currentPrices = tm.GetPriceSnapshot() if not currentPrices == None: low = currentPrices.low high = currentPrices.high m = tm.currentDate.month for i in range(tm._tranchCount): available, buyPending, sellPending, longPositions = tm.PositionSummary( ) if m >= SellMonth and m <= BuyMonth: if longPositions > 0: tm.PlaceSell(ticker, high, True) else: break else: if available > 0 and tm.FundsAvailable() > high: tm.PlaceBuy(ticker, low, True) else: break
def RunTradingModelSeasonal(ticker: str, startDate: str, durationInYears: int, totalFunds: int, verbose: bool = False, saveHistoryToFile: bool = True, returndailyValues: bool = False): modelName = 'Seasonal' + '_' + ticker tm = TradingModel(modelName, ticker, startDate, durationInYears, totalFunds, verbose) if not tm.modelReady: print('Unable to initialize price history for model for ' + str(startDate)) if returndailyValues: return pandas.DataFrame() else: return totalFunds else: while not tm.ModelCompleted(): tm.ProcessDay() currentPrices = tm.GetPriceSnapshot() if not currentPrices == None: low = currentPrices.low high = currentPrices.high m = tm.currentDate.month available, buyPending, sellPending, longPositions = tm.GetPositionSummary( ) if m >= 11 or m <= 4: #Buy if Nov through April, else sell if available > 0 and tm.FundsAvailable() > high: tm.PlaceBuy(ticker, low, True) else: if longPositions > 0: tm.PlaceSell(ticker, high, True) if tm.AccountingError(): break if returndailyValues: tm.CloseModel(verbose, saveHistoryToFile) return tm.GetdailyValue() #return daily value else: return tm.CloseModel(verbose, saveHistoryToFile) #return closing value
def RunTradingModelFirstHalfOfMonth(tm: TradingModel, ticker: str): #From Robert Ariel's observations, most gains are in the first half of the month BuyDay = 25 #Buy at the end of the month, after the 25th SellDay = 15 #Sell mid month, after the 15th currentPrices = tm.GetPriceSnapshot() if not currentPrices == None: low = currentPrices.low high = currentPrices.high d = tm.currentDate.day for i in range(tm._tranchCount): available, buyPending, sellPending, longPositions = tm.PositionSummary( ) if d >= BuyDay or d < 3: if available > 0 and tm.FundsAvailable() > high: tm.PlaceBuy(ticker, low, True) else: break elif d >= SellDay: if longPositions > 0: tm.PlaceSell(ticker, high, True) else: break else: break
def RunTradingModelSwingTrend(ticker: str, startDate: str, durationInYears: int, totalFunds: int, verbose: bool = False, saveHistoryToFile: bool = True, returndailyValues: bool = False): #Give it a date range, some money, and a stock, it will execute a strategy and return the results #minDeviationToTrade = .025 minActionableSlope = 0.002 trendState = 'Flat' #++,--,+-,-+,Flat prevTrendState = '' trendDuration = 0 modelName = 'SwingTrend' + '_' + ticker tm = TradingModel(modelName, ticker, startDate, durationInYears, totalFunds, verbose) if not tm.modelReady: print('Unable to initialize price history for model for ' + str(startDate)) if returndailyValues: return pandas.DataFrame() else: return totalFunds else: while not tm.ModelCompleted(): tm.ProcessDay() p = tm.GetPriceSnapshot() if not p == None: available, buyPending, sellPending, longPositions = tm.GetPositionSummary( ) maxPositions = available + buyPending + sellPending + longPositions targetBuy = p.nextDayTarget * (1 + p.fiveDayDeviation / 2) targetSell = p.nextDayTarget * (1 - p.fiveDayDeviation / 2) if p.longEMASlope >= minActionableSlope and p.shortEMASlope >= minActionableSlope: #++ Positive trend, 70% long trendState = '++' if p.low > p.channelHigh: #Over Bought if sellPending < 3 and longPositions > 7: tm.PlaceSell(ticker, targetSell * (1.03), False, 10) elif p.low < p.channelLow: #Still early if buyPending < 3 and longPositions < 6: tm.PlaceBuy(ticker, targetBuy, True) if trendDuration > 1 and buyPending < 3: tm.PlaceBuy(ticker, targetBuy, True) else: if buyPending < 3 and longPositions < 6: tm.PlaceBuy(ticker, targetBuy, False) if buyPending < 5 and longPositions < maxPositions: tm.PlaceBuy(ticker, targetBuy, False) elif p.longEMASlope >= minActionableSlope and p.shortEMASlope < minActionableSlope: #+- Correction or early downturn trendState = '+-' if p.low > p.channelHigh: #Over Bought, try to get out if sellPending < 3 and longPositions > 7: tm.PlaceSell(ticker, targetSell, False, 3) elif p.low < p.channelLow and p.high > p.channelLow: #Deep correction if sellPending < 3 and longPositions > 7: tm.PlaceSell(ticker, targetSell, False, 3) else: pass elif p.longEMASlope < -minActionableSlope and p.shortEMASlope < -minActionableSlope: #-- Negative trend, aim for < 30% long trendState = '--' if p.high < p.channelLow: #Over sold if buyPending < 3 and longPositions < 6: tm.PlaceBuy(ticker, targetBuy * .95, False, 2) elif p.low < p.channelLow and p.high > p.channelLow: #Straddle Low, early down or up pass else: if sellPending < 5 and longPositions > 3: tm.PlaceSell(ticker, targetSell, True) if trendDuration > 1: tm.PlaceSell(ticker, targetSell, True) if sellPending < 5 and longPositions > 3: tm.PlaceSell(ticker, targetSell, False, 2) tm.PlaceSell(ticker, targetSell, False, 2) elif p.longEMASlope < ( -1 * minActionableSlope) and p.shortEMASlope < ( -1 * minActionableSlope): #-+ Bounce or early recovery trendState = '-+' if p.high < p.channelLow: #Over sold pass elif p.low < p.channelLow and p.high > p.channelLow: #Straddle Low if sellPending < 3 and longPositions > 3: tm.PlaceSell(ticker, targetSell, False, 3) else: pass else: #flat, aim for 70% long trendState = 'Flat' if p.low > p.channelHigh: #Over Bought if sellPending < 3 and longPositions > 7: tm.PlaceSell(ticker, targetSell * (1.03), False, 10) elif p.high < p.channelLow: #Over sold if buyPending < 3 and longPositions < 8: tm.PlaceBuy(ticker, targetBuy, False, 5) if buyPending < 4: tm.PlaceBuy(ticker, targetBuy, False, 5) else: pass if sellPending < 3 and longPositions > 7: tm.PlaceSell(ticker, targetSell, False, 5) if buyPending < 3 and longPositions < maxPositions: tm.PlaceBuy(ticker, targetBuy, False, 5) if trendState == prevTrendState: trendDuration = trendDuration + 1 else: trendDuration = 0 if tm.AccountingError(): break if returndailyValues: tm.CloseModel(verbose, saveHistoryToFile) return tm.GetdailyValue() #return daily value else: return tm.CloseModel(verbose, saveHistoryToFile) #return closing value
def RunTradingModelSwingTrend(tm: TradingModel, ticker: str): #Combines trending model with targeted "swing" buys, attempting to gain better deals by anticipating daily price fluctuations minActionableSlope = 0.002 prevTrendState, trendDuration = tm.GetCustomValues() if prevTrendState == None: prevTrendState = '' if trendDuration == None: trendDuration = 0 p = tm.GetPriceSnapshot() if not p == None: for i in range(tm._tranchCount): available, buyPending, sellPending, longPositions = tm.PositionSummary( ) maxPositions = available + buyPending + sellPending + longPositions targetBuy = p.nextDayTarget * (1 + p.fiveDayDeviation / 2) targetSell = p.nextDayTarget * (1 - p.fiveDayDeviation / 2) if p.longEMASlope >= minActionableSlope and p.shortEMASlope >= minActionableSlope: #++ Positive trend, 70% long trendState = '++' if p.low > p.channelHigh: #Over Bought if sellPending < 3 and longPositions > 7: tm.PlaceSell(ticker, targetSell * (1.03), False, 10) elif p.low < p.channelLow: #Still early if buyPending < 3 and longPositions < 6: tm.PlaceBuy(ticker, targetBuy, True) if trendDuration > 1 and buyPending < 3: tm.PlaceBuy(ticker, targetBuy, True) else: if buyPending < 3 and longPositions < 6: tm.PlaceBuy(ticker, targetBuy, False) if buyPending < 5 and longPositions < maxPositions: tm.PlaceBuy(ticker, targetBuy, False) elif p.longEMASlope >= minActionableSlope and p.shortEMASlope < minActionableSlope: #+- Correction or early downturn trendState = '+-' if p.low > p.channelHigh: #Over Bought, try to get out if sellPending < 3 and longPositions > 7: tm.PlaceSell(ticker, targetSell, False, 3) elif p.low < p.channelLow and p.high > p.channelLow: #Deep correction if sellPending < 3 and longPositions > 7: tm.PlaceSell(ticker, targetSell, False, 3) else: pass elif p.longEMASlope < -minActionableSlope and p.shortEMASlope < -minActionableSlope: #-- Negative trend, aim for < 30% long trendState = '--' if p.high < p.channelLow: #Over sold if buyPending < 3 and longPositions < 6: tm.PlaceBuy(ticker, targetBuy * .95, False, 2) elif p.low < p.channelLow and p.high > p.channelLow: #Straddle Low, early down or up pass else: if sellPending < 5 and longPositions > 3: tm.PlaceSell(ticker, targetSell, True) if trendDuration > 1: tm.PlaceSell(ticker, targetSell, True) if sellPending < 5 and longPositions > 3: tm.PlaceSell(ticker, targetSell, False, 2) tm.PlaceSell(ticker, targetSell, False, 2) elif p.longEMASlope < ( -1 * minActionableSlope) and p.shortEMASlope < ( -1 * minActionableSlope): #-+ Bounce or early recovery trendState = '-+' if p.high < p.channelLow: #Over sold pass elif p.low < p.channelLow and p.high > p.channelLow: #Straddle Low if sellPending < 3 and longPositions > 3: tm.PlaceSell(ticker, targetSell, False, 3) else: pass else: #flat, aim for 70% long trendState = 'Flat' if p.low > p.channelHigh: #Over Bought if sellPending < 3 and longPositions > 7: tm.PlaceSell(ticker, targetSell * (1.03), False, 10) elif p.high < p.channelLow: #Over sold if buyPending < 3 and longPositions < 8: tm.PlaceBuy(ticker, targetBuy, False, 5) if buyPending < 4: tm.PlaceBuy(ticker, targetBuy, False, 5) else: pass if sellPending < 3 and longPositions > 7: tm.PlaceSell(ticker, targetSell, False, 5) if buyPending < 3 and longPositions < maxPositions: tm.PlaceBuy(ticker, targetBuy, False, 5) if trendState == prevTrendState: trendDuration = trendDuration + 1 else: trendDuration = 0 tm.SetCustomValues(prevTrendState, trendDuration)
def RunTradingModelTrending(tm: TradingModel, ticker: str): #This compares the slope of short term (6 day) and long term (18 day) exponential moving averages to determine buying opportunities. Positive, negative, or flat slopes #trend states: ++,--,+-,-+,Flat minActionableSlope = 0.002 prevTrendState, trendDuration = tm.GetCustomValues() if prevTrendState == None: prevTrendState = '' if trendDuration == None: trendDuration = 0 p = tm.GetPriceSnapshot() if not p == None: available, buyPending, sellPending, longPositions = tm.PositionSummary( ) maxPositions = available + buyPending + sellPending + longPositions targetBuy = p.nextDayTarget * (1 + p.fiveDayDeviation / 2) targetSell = p.nextDayTarget * (1 - p.fiveDayDeviation / 2) for i in range(tm._tranchCount): if p.longEMASlope >= minActionableSlope and p.shortEMASlope >= minActionableSlope: #++ Positive trend, 100% long trendState = '++' if p.low > p.channelHigh: #Over Bought pass elif p.low < p.channelLow: #Still early if buyPending < 3 and longPositions < 6: tm.PlaceBuy(ticker, targetBuy, True) if trendDuration > 1 and buyPending < 3: tm.PlaceBuy(ticker, targetBuy, True) else: if buyPending < 3 and longPositions < 6: tm.PlaceBuy(ticker, targetBuy, True) if buyPending < 5 and longPositions < maxPositions: tm.PlaceBuy(ticker, targetBuy, False, 3) elif p.longEMASlope >= minActionableSlope and p.shortEMASlope < minActionableSlope: #+- Correction or early downturn trendState = '+-' if p.low > p.channelHigh: #Over Bought, try to get out if sellPending < 3 and longPositions > 7: tm.PlaceSell(ticker, targetSell * .98, False, 3) elif p.low < p.channelLow and p.high > p.channelLow: #Deep correction if sellPending < 3 and longPositions > 7: tm.PlaceSell(ticker, targetSell, False, 3) else: pass elif p.longEMASlope < -minActionableSlope and p.shortEMASlope < -minActionableSlope: #-- Negative trend, get out trendState = '--' if p.high < p.channelLow: #Over sold if buyPending < 3 and longPositions < 6: tm.PlaceBuy(ticker, targetBuy * .95, False, 2) elif p.low < p.channelLow and p.high > p.channelLow: #Straddle Low, possible early up pass else: if trendDuration > 2: if sellPending < 5 and longPositions > 5: tm.PlaceSell(ticker, targetSell, True) if sellPending < 5 and longPositions > 0: tm.PlaceSell(ticker, targetSell, True) if sellPending < 5 and longPositions > 3: tm.PlaceSell(ticker, targetSell, False, 2) tm.PlaceSell(ticker, targetSell, False, 2) elif p.longEMASlope < ( -1 * minActionableSlope) and p.shortEMASlope < ( -1 * minActionableSlope): #-+ Bounce or early recovery trendState = '-+' if p.high < p.channelLow: #Over sold if buyPending < 3 and longPositions < 6: tm.PlaceBuy(ticker, targetBuy * .95, False, 2) elif p.low < p.channelLow and p.high > p.channelLow: #Straddle Low if buyPending < 3 and longPositions < 6: tm.PlaceBuy(ticker, targetBuy * .95, False, 2) else: pass else: #flat, aim for 70% long trendState = 'Flat' if p.low > p.channelHigh: #Over Bought pass elif p.high < p.channelLow: #Over sold if buyPending < 3 and longPositions < 8: tm.PlaceBuy(ticker, targetBuy, False, 5) if buyPending < 4: tm.PlaceBuy(ticker, targetBuy, False, 5) else: pass if buyPending < 3 and longPositions < maxPositions: tm.PlaceBuy(ticker, targetBuy, False, 5) tm.SetCustomValues(trendState, trendDuration) if trendState == prevTrendState: trendDuration = trendDuration + 1 else: trendDuration = 0 tm.SetCustomValues(prevTrendState, trendDuration)
def RunTradingModelSwingTrend(tm: TradingModel, ticker: str): #Give it a date range, some money, and a stock, it will execute a strategy and return the results #minDeviationToTrade = .025 minActionableSlope = 0.002 prevTrendState, trendDuration = tm.GetCustomValues() if prevTrendState == None: prevTrendState = '' if trendDuration == None: trendDuration = 0 p = tm.GetPriceSnapshot() if not p == None: available, buyPending, sellPending, longPositions = tm.PositionSummary( ) maxPositions = available + buyPending + sellPending + longPositions targetBuy = p.nextDayTarget * (1 + p.fiveDayDeviation / 2) targetSell = p.nextDayTarget * (1 - p.fiveDayDeviation / 2) if p.longEMASlope >= minActionableSlope and p.shortEMASlope >= minActionableSlope: #++ Positive trend, 70% long trendState = '++' if p.low > p.channelHigh: #Over Bought if sellPending < 3 and longPositions > 7: tm.PlaceSell(ticker, targetSell * (1.03), False, 10) elif p.low < p.channelLow: #Still early if buyPending < 3 and longPositions < 6: tm.PlaceBuy(ticker, targetBuy, True) if trendDuration > 1 and buyPending < 3: tm.PlaceBuy(ticker, targetBuy, True) else: if buyPending < 3 and longPositions < 6: tm.PlaceBuy(ticker, targetBuy, False) if buyPending < 5 and longPositions < maxPositions: tm.PlaceBuy(ticker, targetBuy, False) elif p.longEMASlope >= minActionableSlope and p.shortEMASlope < minActionableSlope: #+- Correction or early downturn trendState = '+-' if p.low > p.channelHigh: #Over Bought, try to get out if sellPending < 3 and longPositions > 7: tm.PlaceSell(ticker, targetSell, False, 3) elif p.low < p.channelLow and p.high > p.channelLow: #Deep correction if sellPending < 3 and longPositions > 7: tm.PlaceSell(ticker, targetSell, False, 3) else: pass elif p.longEMASlope < -minActionableSlope and p.shortEMASlope < -minActionableSlope: #-- Negative trend, aim for < 30% long trendState = '--' if p.high < p.channelLow: #Over sold if buyPending < 3 and longPositions < 6: tm.PlaceBuy(ticker, targetBuy * .95, False, 2) elif p.low < p.channelLow and p.high > p.channelLow: #Straddle Low, early down or up pass else: if sellPending < 5 and longPositions > 3: tm.PlaceSell(ticker, targetSell, True) if trendDuration > 1: tm.PlaceSell(ticker, targetSell, True) if sellPending < 5 and longPositions > 3: tm.PlaceSell(ticker, targetSell, False, 2) tm.PlaceSell(ticker, targetSell, False, 2) elif p.longEMASlope < (-1 * minActionableSlope) and p.shortEMASlope < ( -1 * minActionableSlope): #-+ Bounce or early recovery trendState = '-+' if p.high < p.channelLow: #Over sold pass elif p.low < p.channelLow and p.high > p.channelLow: #Straddle Low if sellPending < 3 and longPositions > 3: tm.PlaceSell(ticker, targetSell, False, 3) else: pass else: #flat, aim for 70% long trendState = 'Flat' if p.low > p.channelHigh: #Over Bought if sellPending < 3 and longPositions > 7: tm.PlaceSell(ticker, targetSell * (1.03), False, 10) elif p.high < p.channelLow: #Over sold if buyPending < 3 and longPositions < 8: tm.PlaceBuy(ticker, targetBuy, False, 5) if buyPending < 4: tm.PlaceBuy(ticker, targetBuy, False, 5) else: pass if sellPending < 3 and longPositions > 7: tm.PlaceSell(ticker, targetSell, False, 5) if buyPending < 3 and longPositions < maxPositions: tm.PlaceBuy(ticker, targetBuy, False, 5) if trendState == prevTrendState: trendDuration = trendDuration + 1 else: trendDuration = 0 tm.SetCustomValues(prevTrendState, trendDuration)