def get_indicators(self, df: pd.DataFrame) -> pd.DataFrame: # atr df['atr'] = indicators.atr(df, self.atr_periods) # breakout signal df['breakout_s'] = indicators.min_max_signal(df.price, self.periods) # rsi signal df['rsi'] = indicators.rsi(df.price, self.rsi_periods) df['carver_rsi'] = indicators.carver(df['rsi'], 100).rolling( self.rsi_smooth).mean() df['rsi_s'] = indicators.range_crosser(df['carver_rsi'], self.rsi_threshold) # combined signal df['signal'] = df['breakout_s'] + df['rsi_s'] # moving average filter df['ema_fast'] = df.price.ewm(span=self.ema_fast, min_periods=int(self.ema_fast * .6)).mean() df['ema_slow'] = df.price.ewm(span=self.ema_slow, min_periods=int(self.ema_slow * .6)).mean() df['filter'] = np.sign(df['ema_fast'] - df['ema_slow']) df['filtered_signal'] = df['signal'] * \ ((df['signal'] * df['filter']) == 1) return df
def position_size_stop_loss(self, position_type): try: ''' Lot Number of unit Standard 100,000 Mini 10,000 Micro 1,000 Nano 100 Position size = ((account value x risk per trade) / pips risked)/ pip value per standard lot Margin Requirement = Current Price × Units Traded × Margin ''' data=self.db.query_price_data(self.symbol, self.timeframe, self.atr_period*2) data['atr']=atr(list(data.bidclose), self.atr_period) last_atr=data.atr.iloc[-1] price=data.bidclose.iloc[-1] fxcm_info=self.get_account_info()[0] balance=fxcm_info[2] stop_loss, limit, stop_loss_pip, limit_pip=self.stop_loss_limit(price, last_atr, position_type) leverage=leverage_cal(self.symbol, balance) standard_lot_pip_value=pip_value_cal(self.symbol, self.account_currency, price, 100000) position_size=int(((((balance*self.risk_percent/100)/stop_loss_pip)/standard_lot_pip_value)*100)*1000) required_margin=int(price*position_size/leverage) c = CurrencyConverter() required_margin=int(c.convert(required_margin, self.symbol[:3], self.account_currency)) if self.symbol[3:]=='JPY': required_margin=required_margin/100 return position_size/1000, required_margin, stop_loss, limit, stop_loss_pip, limit_pip except Exception as e: print(e, 'position_size_stop_loss')
def backtest(self, position_type, data, margin): try: ''' Lot Number of unit Standard 100,000 Mini 10,000 Micro 1,000 Nano 100 Position size = ((account value x risk per trade) / pips risked)/ pip value per standard lot Margin Requirement = Current Price × Units Traded × Margin ''' data['atr']=atr(list(data.bidclose), self.atr_period) last_atr=data.atr.iloc[-1] price=data.bidclose.iloc[-1] stop_loss, limit, stop_loss_pip, limit_pip=self.stop_loss_limit(price, last_atr, position_type) leverage=leverage_cal(self.symbol, margin) standard_lot_pip_value=pip_value_cal(self.symbol, self.account_currency, price, 100000) position_size=int(((((margin*self.risk_percent/100)/stop_loss_pip)/standard_lot_pip_value)*100)*1000) required_margin=int(price*position_size/leverage) c = CurrencyConverter() required_margin=int(c.convert(required_margin, self.symbol[:3], self.account_currency)) pip_value=pip_value_cal(self.symbol, self.account_currency, price, position_size) if self.symbol[3:]=='JPY': required_margin=required_margin/100 return position_size, required_margin, stop_loss, limit, stop_loss_pip, limit_pip, pip_value except Exception as e: print(e, 'backtest')
def check_condition_stop(self, position_type): if self.economic_calendar.empty: self.update_economic_calendar() if self.economic_calendar.empty: return False if utc_to_central_time( self.last_update_time).day != utc_to_central_time( datetime.datetime.utcnow()).day: self.update_economic_calendar() now_utc = datetime.datetime.utcnow() check_time_ahead = now_utc + self.time_to_change_stop_loss_before_news if self.economic_calendar.loc[ (self.economic_calendar['date'] > now_utc) & (self.economic_calendar['date'] < check_time_ahead) & (self.economic_calendar['impact'].isin(self.impact_list_to_watch)) & (self.economic_calendar['currency'].str.contains( self.symbol))].empty: data = self.db.query_price_data(self.symbol, self.timeframe, self.atr_period * 2) data['atr'] = atr(list(data.bidclose), self.atr_period) last_atr = data.atr.iloc[-1] price = data.bidclose.iloc[-1] if position_type == 'buy': stop_loss = price - last_atr * self.stop_loss_atr_multiply return stop_loss else: stop_loss = price + last_atr * self.stop_loss_atr_multiply return stop_loss else: return False #No need to change stop loss
def FTShort( minRejectAtr = 0.3, hodHoldMinBars = 5 ): hod = ind.hodExtended(bars).shift(1) # use hod 1 bar behind BO bar bo = ( bars['H'] > hod ) & __minBarsHeld( hod, hodHoldMinBars ) atrDiff = ind.atr( bars).shift(1) * minRejectAtr # Min rejection distance ftSameBar = bo & ( (hod-bars['C']) > atrDiff ) ftnextBar = bo.shift(1) & ( (hod.shift(1)-bars['C']) > atrDiff ) signal = ftSameBar | ( ftnextBar & (~ftSameBar).shift(1) ) # FT in BO bar Or FT in Next bar without FT in previous bar return signal
def FTLong(minRejectAtr=0.3, lodHoldMinBars=5): lod = ind.lodExtended(bars).shift(1) bo = (bars['L'] < lod) & __minBarsHeld(lod, lodHoldMinBars) atrDiff = ind.atr(bars).shift(1) * minRejectAtr ftSameBar = bo & ((bars['C'] - lod) > atrDiff) ftnextBar = bo.shift(1) & ((bars['C'] - lod.shift(1)) > atrDiff) signal = ftSameBar | (ftnextBar & (~ftSameBar).shift(1)) return signal
def FTLong( minRejectAtr = 0.3, lodHoldMinBars = 5 ): lod = ind.lodExtended(bars).shift(1) bo = ( bars['L'] < lod ) & __minBarsHeld( lod, lodHoldMinBars ) atrDiff = ind.atr( bars).shift(1) * minRejectAtr ftSameBar = bo & ( (bars['C']-lod) > atrDiff ) ftnextBar = bo.shift(1) & ( (bars['C']-lod.shift(1)) > atrDiff ) signal = ftSameBar | ( ftnextBar & (~ftSameBar).shift(1) ) return signal
def get_indicators(self, df: pd.DataFrame) -> pd.DataFrame: df['ema_fast'] = df.price.ewm(span=self.ema_fast, min_periods=int(self.ema_fast * .6)).mean() df['ema_slow'] = df.price.ewm(span=self.ema_slow, min_periods=int(self.ema_slow * .6)).mean() df['atr'] = indicators.atr(df, self.atr_periods) df['signal'] = indicators.any_signal(df.price, self.periods) df['filter'] = np.sign(df['ema_fast'] - df['ema_slow']) df['filtered_signal'] = df['signal'] * \ ((df['signal'] * df['filter']) == 1) return df
def FTShort(minRejectAtr=0.3, hodHoldMinBars=5): hod = ind.hodExtended(bars).shift(1) # use hod 1 bar behind BO bar bo = (bars['H'] > hod) & __minBarsHeld(hod, hodHoldMinBars) atrDiff = ind.atr(bars).shift(1) * minRejectAtr # Min rejection distance ftSameBar = bo & ((hod - bars['C']) > atrDiff) ftnextBar = bo.shift(1) & ((hod.shift(1) - bars['C']) > atrDiff) signal = ftSameBar | ( ftnextBar & (~ftSameBar).shift(1) ) # FT in BO bar Or FT in Next bar without FT in previous bar return signal
def get_indicators(self, df: pd.DataFrame) -> pd.DataFrame: df['atr'] = indicators.atr(df, self.atr_periods) df['mid'] = df.price.ewm(span=self.bollinger_periods).mean() df['std'] = df['price'].ewm(span=self.bollinger_periods).std() df['upper'] = df['mid'] + 1 * df['std'] df['lower'] = df['mid'] - 1 * df['std'] df['up'] = (df['price'] > df['upper'].shift()) * 1 df['down'] = (df['price'] < df['lower'].shift()) * -1 df['signal'] = df['up'] + df['down'] df['filtered_signal'] = df['signal'] df['direction'] = np.sign(df['price'] - df['mid']) df['close_signal'] = ( (df['direction'] * df['direction'].shift()) < 0) * df['direction'] return df
def get_indicators(self, df: pd.DataFrame) -> pd.DataFrame: df['rsi'] = indicators.rsi(df.price, 24) df['carver_rsi'] = indicators.carver(df['rsi'], 100).rolling(15).mean() df['signal'] = indicators.range_crosser(df['carver_rsi'], 60) df['ema_fast'] = df.price.ewm(span=self.ema_fast, min_periods=int(self.ema_fast * .6)).mean() df['ema_slow'] = df.price.ewm(span=self.ema_slow, min_periods=int(self.ema_slow * .6)).mean() df['atr'] = indicators.atr(df, self.atr_periods) df['filter'] = np.sign(df['ema_fast'] - df['ema_slow']) df['filtered_signal'] = df['signal'] * \ ((df['signal'] * df['filter']) == 1) return df
def _getInitStopATR( self, trade, bars, tradeBarIndex ): atr = indicators.atr( bars, s.MECHTM_STOP_ATR_LOOKBACK ) previousBarIndex = tradeBarIndex - datetime.timedelta(minutes=5) # Use previous bar's ATR if( s.MECHTM_STOP_MAX_ATR_LOOKBACK > 1 ): # Use Highest atr within lookback atr = atr.rolling( s.MECHTM_STOP_MAX_ATR_LOOKBACK, min_periods=s.MECHTM_STOP_MAX_ATR_LOOKBACK ).max() stopATR = atr[previousBarIndex] entry = trade.PriceIn if( trade.isLong ): stop = entry - stopATR * s.MECHTM_STOP_ATR_MULTIPLIER else: stop = entry + stopATR * s.MECHTM_STOP_ATR_MULTIPLIER return stop
def addIndicators(s): stks = deepcopy(s) #stks['trade_count'] = 0 #stks['signal'] = '' #stks['DailyReturn'] = '' #stks['DailyReturn'] = stks['DailyReturn'].apply(list) for ticker, stk in stks.items(): print('Adding indicators for', ticker) df = stk['data'] df['Stoch'] = ind.stochasticOsc(df)['%K'] df['MACD'] = ind.macd(df)['MACD'] df['MacdSignal'] = ind.macd(df)['Signal'] df['ATR'] = ind.atr(df, period=60)['ATR'] df.dropna(inplace=True) df.reset_index(drop=True, inplace=True) signal[ticker] = '' pct_change[ticker] = [0] trade_count[ticker] = 0 return stks
def get_indicators(self, df: pd.DataFrame) -> pd.DataFrame: df['ema_fast'] = df.price.ewm(span=self.ema_fast, min_periods=int(self.ema_fast * .6)).mean() df['ema_slow'] = df.price.ewm(span=self.ema_slow, min_periods=int(self.ema_slow * .6)).mean() df['atr'] = indicators.atr(df, self.atr_periods) df['signal'] = indicators.min_max_signal(df.price, self.periods) df['filter'] = np.sign(df['ema_fast'] - df['ema_slow']) df['pre_lock'] = df['signal'] * ((df['signal'] * df['filter']) == 1) df['lock'] = (( (df.pre_lock.shift().rolling(self.lock_periods).min() + df.pre_lock.shift().rolling(self.lock_periods).max())) + df.pre_lock.shift()).clip(-1, 1) df['filtered_signal'] = (df['pre_lock'] * ~((df['pre_lock'] * df['lock']) == 1)) return df
def _getInitStopATR(self, trade, bars, tradeBarIndex): atr = indicators.atr(bars, s.MECHTM_STOP_ATR_LOOKBACK) previousBarIndex = tradeBarIndex - datetime.timedelta( minutes=5) # Use previous bar's ATR if (s.MECHTM_STOP_MAX_ATR_LOOKBACK > 1): # Use Highest atr within lookback atr = atr.rolling( s.MECHTM_STOP_MAX_ATR_LOOKBACK, min_periods=s.MECHTM_STOP_MAX_ATR_LOOKBACK).max() stopATR = atr[previousBarIndex] entry = trade.PriceIn if (trade.isLong): stop = entry - stopATR * s.MECHTM_STOP_ATR_MULTIPLIER else: stop = entry + stopATR * s.MECHTM_STOP_ATR_MULTIPLIER return stop
def get_indicators(self, df: pd.DataFrame) -> pd.DataFrame: df['atr'] = indicators.atr(df, self.atr_periods) df['ema_fast'] = df.price.ewm(span=self.ema_fast, min_periods=int(self.ema_fast * .6)).mean() df['ema_slow'] = df.price.ewm(span=self.ema_slow, min_periods=int(self.ema_slow * .6)).mean() df['ema_filter'] = np.sign(df['ema_fast'] - df['ema_slow']) df['ema_slow_diff'] = df['ema_slow'].diff().abs() df['vol_slow'] = df['price'].ewm(span=self.ema_slow).std() df['strength_slow'] = (df['ema_slow_diff'] / df['vol_slow']) * 100 df['strength_slow_median'] = df['strength_slow'].expanding().median() df['strength_filter'] = (df['strength_slow'] >= df['strength_slow_median']) df['signal'] = indicators.min_max_signal(df.price, self.periods) df['pre_strength'] = df['signal'] * \ ((df['signal'] * df['ema_filter']) == 1) df['filtered_signal'] = df['pre_strength'] * df['strength_filter'] return df
def _processScrip(self, scrip): pd.options.mode.chained_assignment = None # Hide warning on sliced data update. We dont need to update it back to source if (scrip in s.MECHTM_IGNORE_SCRIPS): # Ignore trades in some scrips return [] # -- Load Trade Database -- try: bars = database.loadScripRandomDB( scrip) if s.DB_RANDOM else database.loadScripDB(scrip) except IOError: print(scrip, " Not Found") return None # -- Load Trade Log or generate tradelog from Mech signal -- scripTrades = self._loadTradesForScrip(scrip, bars) if (s.MECHTM_ISTRAIL_ENABLED ): # Calculate atr array once per scrip - used for atr trail trailAtr = indicators.atr(bars, s.MECHTM_TRAIL_ATR_LOOKBACK) if ( s.MECHTM_CALLBACK_SCRIP_CHANGE_FN is not None ): # Callback to allow setting up per scrip datastuctures that can be used for bar-by-bar callbacks s.MECHTM_CALLBACK_SCRIP_CHANGE_FN(bars) # -- For each trade, go bar by bar and look for exit rule outputTrades = [ ] # Make list of dictionary. These trades will be used to write output csv for trade in scripTrades.itertuples(): barsAfterEntry, tradeBarIndex = self._locateTrade( bars, trade) # Locate Trade bar in database # -- Start Mech TM -- entry = trade.PriceIn if (s.MECHTM_STOP_OVERRIDE): initStop = self._getInitStopATR(trade, bars, tradeBarIndex) else: initStop = trade.InitStop diff = trade.PriceInTrigger - initStop # Projecting target from triggered price similar to Live target = trade.PriceInTrigger + s.MECHTM_TARGET_X * diff stop = initStop firstBar = barsAfterEntry.iloc[0] closePrice = firstBar['C'] extremePrice = firstBar['H'] if trade.isLong else firstBar['L'] if (abs(closePrice - entry) / entry > 0.01): # Split/Bonus etc issues. Detect difference > 1% print(scrip, "Large Price difference. Database Price:", closePrice, "Trade Entry Price:", entry) barsHeld = 0 # Trade Holding Time, might show 1 extra bar due to workaround above if ( s.MECHTM_CALLBACK_TRADE_CHANGE_FN is not None ): # Callback to allow setting up per trade datastuctures that can be used for bar-by-bar callbacks s.MECHTM_CALLBACK_TRADE_CHANGE_FN(trade, firstBar) for bar in barsAfterEntry.itertuples( ): # Iterate bar by bar after entry and look for exit barsHeld += 1 if (self.isMechEntry and barsHeld == 1): # Mech Trades are on close, ignore 1st bar continue closedTrade = self._stopHit(trade, bar, stop) if (closedTrade): # Stop hit ? break closedTrade = self._targetHit(trade, bar, target) # Target hit ? if (closedTrade): break closedTrade = self._timeIsUp(trade, bar) # Exit before 15:20 if (closedTrade): break if (s.MECHTM_CALLBACK_EXIT_FN is not None): # Custom rule to exit trade closedTrade = s.MECHTM_CALLBACK_EXIT_FN( trade, bar, initStop) if (closedTrade): break if (s.MECHTM_CALLBACK_STOP_FN is not None): # Custom rule to update Stop stop = s.MECHTM_CALLBACK_STOP_FN(trade, bar, initStop, stop) if (s.MECHTM_ISTRAIL_ENABLED ): # Trail stop. But never more than InitStop extremePrice = getExtremePrice(trade, bar, extremePrice) distance = trailAtr[ bar. Index] * s.MECHTM_TRAIL_ATR_MULTIPLIER # Use current bar's atr. Stop applies to next bar if (s.MECHTM_TRAIL_MOVE_BACK_STOP): stop = getTrailPrice( trade, bar, initStop, extremePrice, distance) # Dont allow moving behind initStop else: stop = getTrailPrice( trade, bar, stop, extremePrice, distance) # Dont allow moving behind current stop if (stop == bar.C ): # Trailing Stop went ahead of current price closedTrade = markClosedAtCurrentPrice(trade, bar) break if ((trade.isLong and stop < initStop) or (not trade.isLong and stop > initStop)): raise Exception('Stop moved behind initStop') if ((trade.isLong and stop > bar.C) or (not trade.isLong and stop < bar.C)): raise Exception('Stop moved ahead of price') if (closedTrade): closedTrade[ 'InitStop'] = initStop # Add Closed trade to output list closedTrade['BarsHeld'] = barsHeld outputTrades.append(closedTrade) else: print("Trade not closed : ", trade) return outputTrades
def _processScrip( self, scrip ): pd.options.mode.chained_assignment = None # Hide warning on sliced data update. We dont need to update it back to source if( scrip in s.MECHTM_IGNORE_SCRIPS ): # Ignore trades in some scrips return [] # -- Load Trade Database -- try: bars = database.loadScripRandomDB( scrip ) if s.DB_RANDOM else database.loadScripDB( scrip ) except IOError: print( scrip, " Not Found" ) return None # -- Load Trade Log or generate tradelog from Mech signal -- scripTrades = self._loadTradesForScrip( scrip, bars ) if( s.MECHTM_ISTRAIL_ENABLED ): # Calculate atr array once per scrip - used for atr trail trailAtr = indicators.atr( bars, s.MECHTM_TRAIL_ATR_LOOKBACK ) if( s.MECHTM_CALLBACK_SCRIP_CHANGE_FN is not None ): # Callback to allow setting up per scrip datastuctures that can be used for bar-by-bar callbacks s.MECHTM_CALLBACK_SCRIP_CHANGE_FN( bars ) # -- For each trade, go bar by bar and look for exit rule outputTrades = [] # Make list of dictionary. These trades will be used to write output csv for trade in scripTrades.itertuples(): barsAfterEntry, tradeBarIndex = self._locateTrade( bars, trade ) # Locate Trade bar in database # -- Start Mech TM -- entry = trade.PriceIn if( s.MECHTM_STOP_OVERRIDE ): initStop = self._getInitStopATR( trade, bars, tradeBarIndex ) else : initStop = trade.InitStop diff = trade.PriceInTrigger - initStop # Projecting target from triggered price similar to Live target = trade.PriceInTrigger + s.MECHTM_TARGET_X * diff stop = initStop firstBar = barsAfterEntry.iloc[0] closePrice = firstBar['C'] extremePrice = firstBar['H'] if trade.isLong else firstBar['L'] if( abs(closePrice-entry) / entry > 0.01 ): # Split/Bonus etc issues. Detect difference > 1% print( scrip, "Large Price difference. Database Price:", closePrice, "Trade Entry Price:", entry ) barsHeld = 0 # Trade Holding Time, might show 1 extra bar due to workaround above if( s.MECHTM_CALLBACK_TRADE_CHANGE_FN is not None ): # Callback to allow setting up per trade datastuctures that can be used for bar-by-bar callbacks s.MECHTM_CALLBACK_TRADE_CHANGE_FN( trade, firstBar ) for bar in barsAfterEntry.itertuples(): # Iterate bar by bar after entry and look for exit barsHeld += 1 if( self.isMechEntry and barsHeld == 1): # Mech Trades are on close, ignore 1st bar continue closedTrade = self._stopHit( trade, bar, stop ) if( closedTrade ): # Stop hit ? break closedTrade = self._targetHit( trade, bar, target ) # Target hit ? if(closedTrade): break closedTrade = self._timeIsUp( trade, bar ) # Exit before 15:20 if(closedTrade): break if( s.MECHTM_CALLBACK_EXIT_FN is not None ): # Custom rule to exit trade closedTrade = s.MECHTM_CALLBACK_EXIT_FN( trade, bar, initStop ) if(closedTrade): break if( s.MECHTM_CALLBACK_STOP_FN is not None ): # Custom rule to update Stop stop = s.MECHTM_CALLBACK_STOP_FN( trade, bar, initStop, stop ) if( s.MECHTM_ISTRAIL_ENABLED ): # Trail stop. But never more than InitStop extremePrice = getExtremePrice( trade, bar, extremePrice ) distance = trailAtr[bar.Index] * s.MECHTM_TRAIL_ATR_MULTIPLIER # Use current bar's atr. Stop applies to next bar if( s.MECHTM_TRAIL_MOVE_BACK_STOP ): stop = getTrailPrice( trade, bar, initStop, extremePrice, distance ) # Dont allow moving behind initStop else: stop = getTrailPrice( trade, bar, stop, extremePrice, distance ) # Dont allow moving behind current stop if( stop == bar.C ): # Trailing Stop went ahead of current price closedTrade = markClosedAtCurrentPrice( trade, bar ) break if( (trade.isLong and stop < initStop ) or (not trade.isLong and stop > initStop ) ) : raise Exception( 'Stop moved behind initStop' ) if( (trade.isLong and stop > bar.C) or (not trade.isLong and stop < bar.C ) ) : raise Exception( 'Stop moved ahead of price' ) if( closedTrade ): closedTrade['InitStop'] = initStop # Add Closed trade to output list closedTrade['BarsHeld'] = barsHeld outputTrades.append( closedTrade ) else: print( "Trade not closed : ", trade ) return outputTrades
def onScripChange_trailOnSpikeUp(bars): global ss, trailAtr ss = ind.sigmaSpike(bars['C'], 20) trailAtr = ind.atr(bars, 20)
def onScripChange_trailOnSpikeUp( bars ): global ss, trailAtr ss = ind.sigmaSpike(bars['C'], 20 ) trailAtr = ind.atr( bars, 20 )
def get_indicators(self, df: pd.DataFrame) -> pd.DataFrame: df['atr'] = indicators.atr(df, self.atr_periods) df['roc'] = df.price.pct_change(self.roc) df['signal'] = np.sign(df['roc']) df['filtered_signal'] = df['signal'] return df
def onScripChangeTrailAtr( bars ): global trailAtr trailAtr = ind.atr( bars, 20 )
def onScripChangeTrailAtr(bars): global trailAtr trailAtr = ind.atr(bars, 20)