Esempio n. 1
0
def bollinger_bands(dataframe, period=21, stdv=2, field='close', colum_prefix="bb") -> DataFrame:
    from pyti.bollinger_bands import lower_bollinger_band, middle_bollinger_band, upper_bollinger_band
    dataframe["{}_lower".format(colum_prefix)] = lower_bollinger_band(dataframe[field], period, stdv)
    dataframe["{}_middle".format(colum_prefix)] = middle_bollinger_band(dataframe[field], period, stdv)
    dataframe["{}_upper".format(colum_prefix)] = upper_bollinger_band(dataframe[field], period, stdv)

    return dataframe
Esempio n. 2
0
def bollinger(symbol):
	URL = "https://www.alphavantage.co/query?function=TIME_SERIES_DAILY&symbol=" + symbol + "&apikey=" + config.alphaadvantage_api_key_id
	r = requests.get(url = URL)
	data = r.json()
	days = data["Time Series (Daily)"]
	closingPrices = []
	for day in days:
		closingPrices.append(float(days[day]['4. close']))


	cleanedData = []
	period = 2


	upperbands = upper_bollinger_band(closingPrices, 20)
	lowerBands = lower_bollinger_band(closingPrices, 20)

	ub = []
	lb = []

	for upper in upperbands:
		if(math.isnan(upper) == False ):
			ub.append(upper)

	for lower in lowerBands:
		if(math.isnan(lower) == False ):
			lb.append(lower)



	# if current price is greater than upper bound sell
	if(closingPrices[0] >= ub[0]):
			return (1)

	# if current price is lower than lower bound buy
	if(closingPrices[0] <= lb[0]):
			return 1

	# if within 2% of upperband band then sell
	if( (1 - (closingPrices[0] / ub[0]))*100 <= 2 ):
		return 0

	# if within 2% of lower band buy
	if( (1 - (lb[0] / closingPrices[0]))*100 <= 2  ):
		return 0

	# if inside middle range look for trajectory up or down
	if(closingPrices[0] > closingPrices[2]):
		return 1
	else:
		return 0
Esempio n. 3
0
 def get_analysis(self, data, bollinger_function):
     if bollinger_function == 'upper':
         return bollinger_bands.upper_bollinger_band(
             data, self.params['period'])
     if bollinger_function == 'middle':
         return bollinger_bands.middle_bollinger_band(
             data, self.params['period'])
     if bollinger_function == 'lower':
         return bollinger_bands.lower_bollinger_band(
             data, self.params['period'])
     if bollinger_function == 'bandwidth':
         return bollinger_bands.bandwidth(data, self.params['period'])
     if bollinger_function == 'range':
         return bollinger_bands.bb_range(data, self.params['period'])
     if bollinger_function == 'percent_bandwidth':
         return bollinger_bands.percent_bandwidth(data,
                                                  self.params['period'])
     if bollinger_function == 'percent_b':
         return bollinger_bands.percent_b(data, self.params['period'])
Esempio n. 4
0
def Update():
	print(str(dt.datetime.now()) + "	 " + timeframe + " Bar Closed - Running Update Function...")

	# Calculate Indicators
	iBBUpper = bb.upper_bollinger_band(pricedata['bidclose'], bb_periods, bb_standard_deviations)
	iBBMiddle = bb.middle_bollinger_band(pricedata['bidclose'], bb_periods, bb_standard_deviations)
	iBBLower = bb.lower_bollinger_band(pricedata['bidclose'], bb_periods, bb_standard_deviations)
	iADX = adx(pricedata['bidclose'], pricedata['bidhigh'], pricedata['bidlow'], adx_periods)
	
	# Declare simplified variable names for most recent close candle
	close_price = pricedata['bidclose'][len(pricedata)-1]
	BBUpper = iBBUpper[len(iBBUpper)-1]
	BBMiddle = iBBMiddle[len(iBBMiddle)-1]
	BBLower = iBBLower[len(iBBLower)-1]
	ADX = iADX[len(iADX)-1]
	
	# Print Price/Indicators
	print("Close Price: " + str(close_price))
	print("Upper BB: " + str(BBUpper))
	print("Middle BB: " + str(BBMiddle))
	print("Lower BB: " + str(BBLower))
	print("ADX: " + str(ADX))
	
	# TRADING LOGIC
	
	# Change Any Existing Trades' Limits to Middle Bollinger Band
	if countOpenTrades()>0:
		openpositions = con.get_open_positions(kind='list')
		for position in openpositions:
			if position['currency'] == symbol:
				print("Changing Limit for tradeID: " + position['tradeId'])
				try:
					editlimit = con.change_trade_stop_limit(trade_id=position['tradeId'], is_stop=False, rate=BBMiddle, is_in_pips=False)
				except:
					print("	  Error Changing Limit.")
				else:
					print("	  Limit Changed Successfully.")
	
	# Entry Logic
	if ADX < adx_trade_below:
		if countOpenTrades("B") == 0 and close_price < BBLower:
			print("	  BUY SIGNAL!")
			print("	  Opening Buy Trade...")
			stop = pricedata['askclose'][len(pricedata)-1] - (BBMiddle - pricedata['askclose'][len(pricedata)-1])
			limit = BBMiddle
			enter("B", stop, limit)

		if countOpenTrades("S") == 0 and close_price > BBUpper:
			print("	  SELL SIGNAL!")
			print("	  Opening Sell Trade...")
			stop = pricedata['bidclose'][len(pricedata)-1] + (pricedata['bidclose'][len(pricedata)-1] - BBMiddle)
			limit = BBMiddle
			enter("S", stop, limit)

			
	# Exit Logic
	if countOpenTrades("B") > 0 and close_price > BBMiddle:
		print("	  Closing Buy Trade(s)...")
		exit("B")
	if countOpenTrades("S") > 0 and close_price < BBMiddle:
		print("	  Closing Sell Trade(s)...")
		exit("S")

	print(str(dt.datetime.now()) + "	 " + timeframe + " Update Function Completed.\n")
Esempio n. 5
0
 def test_lower_bollinger_bands_invalid_period(self):
     period = 128
     with self.assertRaises(Exception) as cm:
         bollinger_bands.lower_bollinger_band(self.data, period)
     expected = "Error: data_len < period"
     self.assertEqual(str(cm.exception), expected)
Esempio n. 6
0
 def test_lower_bollinger_bands_period_6(self):
     period = 6
     lower_bb = bollinger_bands.lower_bollinger_band(self.data, period)
     np.testing.assert_array_equal(lower_bb,
                                   self.lower_bb_period_6_expected)
Esempio n. 7
0
def calc_feature(data, feature, args):

    #helper function for creating logs
    def replace_zero_with_min(series):
        return series.replace(0, series.loc[series > 0].min())

    import numpy as np
    import pandas as pd
    from pyti import bollinger_bands as bbands

    if feature == "SMA":
        if len(args) != 2:
            raise ValueError("SMA requires 2 args; period and column name")

        return data[args[1]].rolling(int(args[0])).mean()

    elif feature == "BBANDS":
        if len(args) != 4:
            raise ValueError(
                "BBANDS requires 4 args; period, std dev, data_type (1=upper, 2=lower, 3=middle, 4=range) and column name"
            )
        if (int(args[2]) == 1):
            return bbands.upper_bollinger_band(data[args[3]], int(args[0]),
                                               float(args[1]))
        elif (int(args[2]) == 2):
            return bbands.lower_bollinger_band(data[args[3]], int(args[0]),
                                               float(args[1]))
        elif (int(args[2]) == 3):
            return bbands.middle_bollinger_band(data[args[3]], int(args[0]),
                                                float(args[1]))
        elif (int(args[2]) == 4):
            return bbands.bb_range(data[args[3]], int(args[0]), float(args[1]))
        else:
            raise ValueError(
                "BBANDS data_type must be one of (1=upper, 2=lower, 3=middle, 4=range)"
            )

    elif feature == "ATR":
        if len(args) != 4:
            raise ValueError(
                "ATR requires 4 args; period and close column, high column, low column"
            )

        range_table = pd.DataFrame()
        range_table["A"] = data[args[2]] - data[args[3]]
        range_table["B"] = abs(data[args[2]] - data[args[1]].shift(1))
        range_table["C"] = abs(data[args[3]] - data[args[1]].shift(1))
        range_table["max"] = range_table[['A', 'B', 'C']].max(axis=1)

        return range_table["max"].rolling(int(args[0])).mean()

    elif feature == "VOLATILITY_LOG_MA":
        #calculates relative volatility of 12 periods compared to 200 the
        #smooths with a moving average
        if len(args) != 3:
            raise ValueError(
                "ATR requires 3 args; period, high column name, low column name"
            )
        data["volatility_12"] = (data[args[1]] -
                                 data[args[2]]).rolling(12).std()
        data["volatility_200"] = (data[args[1]] -
                                  data[args[2]]).rolling(200).std()
        data["volatility"] = data["volatility_12"] / data["volatility_200"]
        data["volatility_log"] = np.log(
            replace_zero_with_min(data["volatility"]))
        return data["volatility_log"].rolling(int(args[0])).mean()

    elif feature == "VOLUME_LOG_MA":
        if len(args) != 2:
            raise ValueError(
                "VOLUME_LOG_MA requires 2 args; period, column name")
        data["volume_log"] = np.log(replace_zero_with_min(
            data[args[1]])) / np.log(
                replace_zero_with_min(data[args[1]].rolling(200).mean()))
        return data["volume_log"].rolling(int(args[0])).mean()
Esempio n. 8
0
def add_features(asset_data, features=None, save_path=None, verbose=True):
    """ Adds features to the bar data. If no features are passed then all features
    are added.
    
    Args:
        asset_data ((str, pd.DataFrame) or (str, pd.DataFrame)[]): a single 
        or list of tuples (asset name, bar data) containing the bar data
        features (str[]): a list of features to include, all features if this 
            is None
        save_path (str): Path to save the bar data with features. A 
        placeholder {ASSET} that will be substituted with the asset name
        verbose (bool): True if progress printing to console is desired
        
    Returns:
        (str, pd.DataFrame): a single tuple of (asset name, dataframe) of the 
            bar data if a single asset was passed or an array of (asset name, dataframes)
            if an array of assets was passed
    
    """

    #helper function for creating logs
    def replace_zero_with_min(series):
        return series.replace(0, series.loc[series > 0].min())

    import pandas as pd
    import numpy as np
    from pyti import bollinger_bands as bbands
    from pyti import average_true_range as atr

    #if a single dataframe is passed just put it in a single item list
    if type(asset_data) == tuple:
        asset_data = [asset_data]
    elif type(asset_data) != list:
        raise ValueError(
            'asset_data must be a pandas.DataFrame or a list of pandas.Dataframe.'
        )

    feature_bars = []

    for asset, data in asset_data:

        if verbose: print("Calculating features for {0}".format(asset))

        #Lower Bollinger Band, 20 periods, std = 2
        if features == None or 'lower_bb' in features:
            data['lower_bb'] = bbands.lower_bollinger_band(data["close"],
                                                           20,
                                                           std=2.0)

        #Upper Bollinger Band, 20 periods, std = 2
        if features == None or 'upper_bb' in features:
            data['upper_bb'] = bbands.upper_bollinger_band(data["close"],
                                                           20,
                                                           std_mult=2.0)

        #Average True Range
        if features == None or 'atr' in features:
            data["atr"] = atr.average_true_range(data["close"], 24) / \
                atr.average_true_range(data["close"], 200)

        #Volatility is the standard deviation over 12 periods of the difference
        #between high and low of the bar
        if features == None or 'volatility_12' in features:
            data["volatility_12"] = (data["high"] -
                                     data["low"]).rolling(12).std()

        #Volatility is the standard deviation over 200 periods of the difference
        #between high and low of the bar
        if features == None or 'volatility_200' in features:
            data["volatility_200"] = (data["high"] -
                                      data["low"]).rolling(200).std()

        #Volatility is relative change of the alst 12 bars over the last 200
        if features == None or 'volatility' in features:
            data["volatility"] = data["volatility_12"] / data["volatility_200"]

        #Relative volume compared to the last 100 bars
        if features == None or 'volume_change' in features:
            data["volume_change"] = data["volume"] / data["volume"].rolling(
                100).mean()

        #Distance between the close price and the upper bollinger bad
        if features == None or 'bb_dist_upper' in features:
            data["bb_dist_upper"] = data["upper_bb"] - data["close"]

        #Distance between the close price and the lower bollinger bad
        if features == None or 'bb_dist_lower' in features:
            data["bb_dist_lower"] = -(data["lower_bb"] - data["close"])

        #Distance between the upper and lower bollinger bands
        if features == None or 'bb_range' in features:
            data["bb_range"] = (data["upper_bb"] -
                                data["lower_bb"]) / data["close"]

        #The absolute value of the % return over the last 4 bars
        if features == None or 'change_4bar' in features:
            data["change_4bar"] = np.abs(
                np.log(data["close"] / data["close"].shift(4)))

        #The Augmented Dicker Fuller test which can show mean reverting or trending markets
        #from statsmodels.tsa.stattools import adfuller
        #if features == None or 'adf' in features:
        #    data["adf"] = data['Close'].rolling(200).apply(lambda x: adfuller(x)[0], raw=False)

        #The log of the % return
        if features == None or 'log_return' in features:
            data["log_return"] = np.log(data["close"] / data["close"].shift(1))

        #TODO add in the if feature statements
        #add logs - do this by replacing all zeros with the minimum value after zeros are removed
        if 1 == 0:
            data["volume_log"] = np.log(replace_zero_with_min(
                data["volume"])) / np.log(
                    replace_zero_with_min(data["volume"].rolling(200).mean()))
            data["atr_log"] = np.log(replace_zero_with_min(data["atr"]))
            data["volatility_log"] = np.log(
                replace_zero_with_min(data["volatility"]))
            data["change_4bar_log"] = np.log(
                replace_zero_with_min(data["change_4bar"]))

            #add moving averages
            data["volume_log_ma_12"] = data["volume_log"].rolling(12).mean()
            data["volume_log_ma_24"] = data["volume_log"].rolling(24).mean()
            data["volume_log_ma_48"] = data["volume_log"].rolling(48).mean()
            data["volatility_log_ma_12"] = data["volatility_log"].rolling(
                12).mean()
            data["volatility_log_ma_24"] = data["volatility_log"].rolling(
                24).mean()
            data["volatility_log_ma_48"] = data["volatility_log"].rolling(
                48).mean()
            data["change_4bar_log_ma_12"] = data["change_4bar_log"].rolling(
                12).mean()
            data["change_4bar_log_ma_24"] = data["change_4bar_log"].rolling(
                24).mean()
            data["change_4bar_log_ma_48"] = data["change_4bar_log"].rolling(
                48).mean()
            data["log_return_ma_12"] = data["log_return"].rolling(12).mean()
            data["log_return_ma_24"] = data["log_return"].rolling(24).mean()
            data["log_return_ma_48"] = data["log_return"].rolling(48).mean()

        feature_bars.append((asset, data))

        if save_path is not None:
            if verbose: print("Saving {0}...".format(asset))
            save_location = save_path.replace("{ASSET}", asset)
            data.to_csv(save_location)

    #if there was just one dataFrame just return a single dataframe, otherwise
    #return the list of dataframes, one for each asset
    if len(feature_bars) == 1:
        return feature_bars[0]
    else:
        return feature_bars