diff --git a/helper_files/client_helper.py b/helper_files/client_helper.py index b0f9b16..c6350dd 100644 --- a/helper_files/client_helper.py +++ b/helper_files/client_helper.py @@ -5,55 +5,26 @@ from datetime import datetime import logging import yfinance as yf -from strategies.trading_strategies_v2 import ( - rsi_strategy, bollinger_bands_strategy, momentum_strategy, mean_reversion_strategy, - triple_moving_average_strategy, volume_price_trend_strategy, keltner_channel_strategy, - dual_thrust_strategy, adaptive_momentum_strategy, hull_moving_average_strategy, - elder_ray_strategy, chande_momentum_strategy, dema_strategy, price_channel_strategy, - mass_index_strategy, vortex_indicator_strategy, aroon_strategy, ultimate_oscillator_strategy, - trix_strategy, kst_strategy, psar_strategy, stochastic_momentum_strategy, - williams_vix_fix_strategy, conners_rsi_strategy, dpo_strategy, fisher_transform_strategy, - ehlers_fisher_strategy, schaff_trend_cycle_strategy, rainbow_oscillator_strategy, - heikin_ashi_strategy, volume_weighted_macd_strategy, fractal_adaptive_moving_average_strategy, - relative_vigor_index_strategy, center_of_gravity_strategy, kauffman_efficiency_strategy, - phase_change_strategy, volatility_breakout_strategy, momentum_divergence_strategy, - adaptive_channel_strategy, wavelet_decomposition_strategy, entropy_flow_strategy, - bollinger_band_width_strategy, commodity_channel_index_strategy, force_index_strategy, - ichimoku_cloud_strategy, klinger_oscillator_strategy, money_flow_index_strategy, - on_balance_volume_strategy, stochastic_oscillator_strategy, euler_fibonacci_zone_strategy -) -from strategies.trading_strategies_v2_1 import ( - pairs_trading_strategy, kalman_filter_strategy, regime_switching_strategy, adaptive_momentum_filter_strategy, - topological_data_analysis_strategy, levy_distribution_strategy, - wavelet_momentum_strategy, complex_network_strategy, quantum_oscillator_strategy, simple_trend_reversal_strategy -) - -beta_strategies = [pairs_trading_strategy, kalman_filter_strategy, regime_switching_strategy, adaptive_momentum_filter_strategy, - topological_data_analysis_strategy, levy_distribution_strategy, - wavelet_momentum_strategy, complex_network_strategy, quantum_oscillator_strategy, simple_trend_reversal_strategy] - -strategies = [rsi_strategy, bollinger_bands_strategy, momentum_strategy, mean_reversion_strategy, - triple_moving_average_strategy, volume_price_trend_strategy, keltner_channel_strategy, - dual_thrust_strategy, adaptive_momentum_strategy, hull_moving_average_strategy, - elder_ray_strategy, chande_momentum_strategy, dema_strategy, price_channel_strategy, - mass_index_strategy, vortex_indicator_strategy, aroon_strategy, ultimate_oscillator_strategy, - trix_strategy, kst_strategy, psar_strategy, stochastic_momentum_strategy, - williams_vix_fix_strategy, conners_rsi_strategy, dpo_strategy, fisher_transform_strategy, - ehlers_fisher_strategy, schaff_trend_cycle_strategy, rainbow_oscillator_strategy, - heikin_ashi_strategy, volume_weighted_macd_strategy, fractal_adaptive_moving_average_strategy, - relative_vigor_index_strategy, center_of_gravity_strategy, kauffman_efficiency_strategy, - phase_change_strategy, volatility_breakout_strategy, momentum_divergence_strategy, - adaptive_channel_strategy, wavelet_decomposition_strategy, entropy_flow_strategy, - bollinger_band_width_strategy, commodity_channel_index_strategy, force_index_strategy, - ichimoku_cloud_strategy, klinger_oscillator_strategy, money_flow_index_strategy, - on_balance_volume_strategy, stochastic_oscillator_strategy, euler_fibonacci_zone_strategy] + beta_strategies +from strategies.talib_indicators import (BBANDS_indicator, DEMA_indicator, EMA_indicator, HT_TRENDLINE_indicator, KAMA_indicator, MA_indicator, MAMA_indicator, MAVP_indicator, MIDPOINT_indicator, MIDPRICE_indicator, SAR_indicator, SAREXT_indicator, SMA_indicator, T3_indicator, TEMA_indicator, TRIMA_indicator, WMA_indicator, ADX_indicator, ADXR_indicator, APO_indicator, AROON_indicator, AROONOSC_indicator, BOP_indicator, CCI_indicator, CMO_indicator, DX_indicator, MACD_indicator, MACDEXT_indicator, MACDFIX_indicator, MFI_indicator, MINUS_DI_indicator, MINUS_DM_indicator, MOM_indicator, PLUS_DI_indicator, PLUS_DM_indicator, PPO_indicator, ROC_indicator, ROCP_indicator, ROCR_indicator, ROCR100_indicator, RSI_indicator, STOCH_indicator, STOCHF_indicator, STOCHRSI_indicator, TRIX_indicator, ULTOSC_indicator, WILLR_indicator, AD_indicator, ADOSC_indicator, OBV_indicator, HT_DCPERIOD_indicator, HT_DCPHASE_indicator, HT_PHASOR_indicator, HT_SINE_indicator, HT_TRENDMODE_indicator, AVGPRICE_indicator, MEDPRICE_indicator, TYPPRICE_indicator, WCLPRICE_indicator, ATR_indicator, NATR_indicator, TRANGE_indicator, CDL2CROWS_indicator, CDL3BLACKCROWS_indicator, CDL3INSIDE_indicator, CDL3LINESTRIKE_indicator, CDL3OUTSIDE_indicator, CDL3STARSINSOUTH_indicator, CDL3WHITESOLDIERS_indicator, CDLABANDONEDBABY_indicator, CDLADVANCEBLOCK_indicator, CDLBELTHOLD_indicator, CDLBREAKAWAY_indicator, CDLCLOSINGMARUBOZU_indicator, CDLCONCEALBABYSWALL_indicator, CDLCOUNTERATTACK_indicator, CDLDARKCLOUDCOVER_indicator, CDLDOJI_indicator, CDLDOJISTAR_indicator, CDLDRAGONFLYDOJI_indicator, CDLENGULFING_indicator, CDLEVENINGDOJISTAR_indicator, CDLEVENINGSTAR_indicator, CDLGAPSIDESIDEWHITE_indicator, CDLGRAVESTONEDOJI_indicator, CDLHAMMER_indicator, CDLHANGINGMAN_indicator, CDLHARAMI_indicator, CDLHARAMICROSS_indicator, CDLHIGHWAVE_indicator, CDLHIKKAKE_indicator, CDLHIKKAKEMOD_indicator, CDLHOMINGPIGEON_indicator, CDLIDENTICAL3CROWS_indicator, CDLINNECK_indicator, CDLINVERTEDHAMMER_indicator, CDLKICKING_indicator, CDLKICKINGBYLENGTH_indicator, CDLLADDERBOTTOM_indicator, CDLLONGLEGGEDDOJI_indicator, CDLLONGLINE_indicator, CDLMARUBOZU_indicator, CDLMATCHINGLOW_indicator, CDLMATHOLD_indicator, CDLMORNINGDOJISTAR_indicator, CDLMORNINGSTAR_indicator, CDLONNECK_indicator, CDLPIERCING_indicator, CDLRICKSHAWMAN_indicator, CDLRISEFALL3METHODS_indicator, CDLSEPARATINGLINES_indicator, CDLSHOOTINGSTAR_indicator, CDLSHORTLINE_indicator, CDLSPINNINGTOP_indicator, CDLSTALLEDPATTERN_indicator, CDLSTICKSANDWICH_indicator, CDLTAKURI_indicator, CDLTASUKIGAP_indicator, CDLTHRUSTING_indicator, CDLTRISTAR_indicator, CDLUNIQUE3RIVER_indicator, CDLUPSIDEGAP2CROWS_indicator, CDLXSIDEGAP3METHODS_indicator, BETA_indicator, CORREL_indicator, LINEARREG_indicator, LINEARREG_ANGLE_indicator, LINEARREG_INTERCEPT_indicator, LINEARREG_SLOPE_indicator, STDDEV_indicator, TSF_indicator, VAR_indicator) + from urllib.request import urlopen import json import certifi from zoneinfo import ZoneInfo import time +overlap_studies = [BBANDS_indicator, DEMA_indicator, EMA_indicator, HT_TRENDLINE_indicator, KAMA_indicator, MA_indicator, MAMA_indicator, MAVP_indicator, MIDPOINT_indicator, MIDPRICE_indicator, SAR_indicator, SAREXT_indicator, SMA_indicator, T3_indicator, TEMA_indicator, TRIMA_indicator, WMA_indicator] +momentum_indicators = [ADX_indicator, ADXR_indicator, APO_indicator, AROON_indicator, AROONOSC_indicator, BOP_indicator, CCI_indicator, CMO_indicator, DX_indicator, MACD_indicator, MACDEXT_indicator, MACDFIX_indicator, MFI_indicator, MINUS_DI_indicator, MINUS_DM_indicator, MOM_indicator, PLUS_DI_indicator, PLUS_DM_indicator, PPO_indicator, ROC_indicator, ROCP_indicator, ROCR_indicator, ROCR100_indicator, RSI_indicator, STOCH_indicator, STOCHF_indicator, STOCHRSI_indicator, TRIX_indicator, ULTOSC_indicator, WILLR_indicator] +volume_indicators = [AD_indicator, ADOSC_indicator, OBV_indicator] +cycle_indicators = [HT_DCPERIOD_indicator, HT_DCPHASE_indicator, HT_PHASOR_indicator, HT_SINE_indicator, HT_TRENDMODE_indicator] +price_transforms = [AVGPRICE_indicator, MEDPRICE_indicator, TYPPRICE_indicator, WCLPRICE_indicator] +volatility_indicators = [ATR_indicator, NATR_indicator, TRANGE_indicator] +pattern_recognition = [CDL2CROWS_indicator, CDL3BLACKCROWS_indicator, CDL3INSIDE_indicator, CDL3LINESTRIKE_indicator, CDL3OUTSIDE_indicator, CDL3STARSINSOUTH_indicator, CDL3WHITESOLDIERS_indicator, CDLABANDONEDBABY_indicator, CDLADVANCEBLOCK_indicator, CDLBELTHOLD_indicator, CDLBREAKAWAY_indicator, CDLCLOSINGMARUBOZU_indicator, CDLCONCEALBABYSWALL_indicator, CDLCOUNTERATTACK_indicator, CDLDARKCLOUDCOVER_indicator, CDLDOJI_indicator, CDLDOJISTAR_indicator, CDLDRAGONFLYDOJI_indicator, CDLENGULFING_indicator, CDLEVENINGDOJISTAR_indicator, CDLEVENINGSTAR_indicator, CDLGAPSIDESIDEWHITE_indicator, CDLGRAVESTONEDOJI_indicator, CDLHAMMER_indicator, CDLHANGINGMAN_indicator, CDLHARAMI_indicator, CDLHARAMICROSS_indicator, CDLHIGHWAVE_indicator, CDLHIKKAKE_indicator, CDLHIKKAKEMOD_indicator, CDLHOMINGPIGEON_indicator, CDLIDENTICAL3CROWS_indicator, CDLINNECK_indicator, CDLINVERTEDHAMMER_indicator, CDLKICKING_indicator, CDLKICKINGBYLENGTH_indicator, CDLLADDERBOTTOM_indicator, CDLLONGLEGGEDDOJI_indicator, CDLLONGLINE_indicator, CDLMARUBOZU_indicator, CDLMATCHINGLOW_indicator, CDLMATHOLD_indicator, CDLMORNINGDOJISTAR_indicator, CDLMORNINGSTAR_indicator, CDLONNECK_indicator, CDLPIERCING_indicator, CDLRICKSHAWMAN_indicator, CDLRISEFALL3METHODS_indicator, CDLSEPARATINGLINES_indicator, CDLSHOOTINGSTAR_indicator, CDLSHORTLINE_indicator, CDLSPINNINGTOP_indicator, CDLSTALLEDPATTERN_indicator, CDLSTICKSANDWICH_indicator, CDLTAKURI_indicator, CDLTASUKIGAP_indicator, CDLTHRUSTING_indicator, CDLTRISTAR_indicator, CDLUNIQUE3RIVER_indicator, CDLUPSIDEGAP2CROWS_indicator, CDLXSIDEGAP3METHODS_indicator] +statistical_functions = [BETA_indicator, CORREL_indicator, LINEARREG_indicator, LINEARREG_ANGLE_indicator, LINEARREG_INTERCEPT_indicator, LINEARREG_SLOPE_indicator, STDDEV_indicator, TSF_indicator, VAR_indicator] + +strategies = overlap_studies + momentum_indicators + volume_indicators + cycle_indicators + price_transforms + volatility_indicators + pattern_recognition + statistical_functions + # MongoDB connection helper def connect_to_mongo(mongo_url): """Connect to MongoDB and return the client.""" @@ -79,7 +50,6 @@ def place_order(trading_client, symbol, side, qty, mongo_url): ) order = trading_client.submit_order(market_order_data) qty = round(qty, 3) - # Log trade details to MongoDB mongo_client = connect_to_mongo(mongo_url) db = mongo_client.trades @@ -90,8 +60,6 @@ def place_order(trading_client, symbol, side, qty, mongo_url): 'time_in_force': TimeInForce.DAY.name, 'time': datetime.now() }) - - #Track assets as well db = mongo_client.trades assets = db.assets_quantities @@ -105,10 +73,7 @@ def place_order(trading_client, symbol, side, qty, mongo_url): if assets.find_one({'symbol': symbol})['quantity'] == 0: assets.delete_one({'symbol': symbol}) - mongo_client.close() - - - + mongo_client.close() return order # Helper to retrieve NASDAQ-100 tickers from MongoDB @@ -119,8 +84,6 @@ def get_ndaq_tickers(mongo_url, FINANCIAL_PREP_API_KEY): :param mongo_url: MongoDB connection URL :return: List of NASDAQ-100 ticker symbols. """ - - def call_ndaq_100(): """ Fetches the list of NASDAQ 100 tickers using the Financial Modeling Prep API and stores it in a MongoDB collection. @@ -138,7 +101,6 @@ def get_jsonparsed_data(url): response = urlopen(url) data = response.read().decode("utf-8") return json.loads(data) - try: # API URL for fetching NASDAQ 100 tickers ndaq_url = f"https://financialmodelingprep.com/api/v3/nasdaq_constituent?apikey={FINANCIAL_PREP_API_KEY}" @@ -147,7 +109,6 @@ def get_jsonparsed_data(url): except Exception as e: logging.error(f"Error fetching NASDAQ 100 tickers: {e}") return - try: # MongoDB connection details mongo_client = MongoClient(mongo_url) diff --git a/mongo_ b/mongo_ deleted file mode 100644 index e69de29..0000000 diff --git a/mongo_setup.py b/mongo_setup.py deleted file mode 100644 index 14a69fd..0000000 --- a/mongo_setup.py +++ /dev/null @@ -1,90 +0,0 @@ -from config import API_KEY, API_SECRET, POLYGON_API_KEY, RANK_POLYGON_API_KEY, MONGO_DB_USER, MONGO_DB_PASS, mongo_url -from helper_files.client_helper import strategies -from pymongo import MongoClient -import datetime -import math - -def insert_rank_to_coefficient(i): - """ - currently i is at 50 - next i is at 51 - """ - - client = MongoClient(mongo_url) - db = client.trading_simulator - collections = db.rank_to_coefficient - """ - clear all collections entry first and then insert from 1 to i - """ - collections.delete_many({}) - for i in range(1, i + 1): - - e = math.e - rate = (e**e)/(e**2) - 1 - coefficient = rate**(2 * i) - collections.insert_one( - {"rank": i, - "coefficient": coefficient - } - ) - client.close() - -def initialize_rank(): - client = MongoClient(mongo_url) - db = client.trading_simulator - collections = db.algorithm_holdings - - initialization_date = datetime.now() - - - for strategy in strategies: - strategy_name = strategy.__name__ - - - collections = db.algorithm_holdings - - if not collections.find_one({"strategy": strategy_name}): - - collections.insert_one({ - "strategy": strategy_name, - "holdings": {}, - "amount_cash": 50000, - "initialized_date": initialization_date, - "total_trades": 0, - "successful_trades": 0, - "neutral_trades": 0, - "failed_trades": 0, - "last_updated": initialization_date, - "portfolio_value": 50000 - }) - - collections = db.points_tally - collections.insert_one({ - "strategy": strategy_name, - "total_points": 0, - "initialized_date": initialization_date, - "last_updated": initialization_date - }) - - - client.close() - -def initialize_time_delta(): - client = MongoClient(mongo_url) - db = client.trading_simulator - collection = db.time_delta - collection.insert_one({"time_delta": 0.01}) - client.close() - -def initialize_market_setup(): - client = MongoClient(mongo_url) - db = client.market_data - collection = client.market_status - collection.insert_one({"market_status": "closed"}) - client.close() - -if __name__ == "__main__": - insert_rank_to_coefficient(100) - initialize_rank() - initialize_time_delta() - initialize_market_setup() \ No newline at end of file diff --git a/ranking_client.py b/ranking_client.py index 81d7889..79b5da5 100644 --- a/ranking_client.py +++ b/ranking_client.py @@ -2,7 +2,6 @@ from config import POLYGON_API_KEY, FINANCIAL_PREP_API_KEY, MONGO_DB_USER, MONGO_DB_PASS, API_KEY, API_SECRET, BASE_URL, mongo_url import threading from concurrent.futures import ThreadPoolExecutor - from urllib.request import urlopen from zoneinfo import ZoneInfo from pymongo import MongoClient @@ -41,14 +40,14 @@ QueryOrderStatus ) from alpaca.common.exceptions import APIError -import strategies.trading_strategies_v2 as trading_strategies +from strategies.talib_indicators import * import math import yfinance as yf import logging from collections import Counter from trading_client import market_status from helper_files.client_helper import strategies, get_latest_price, get_ndaq_tickers - +import time from datetime import datetime import heapq @@ -63,33 +62,61 @@ ] ) +def process_ticker(ticker, mongo_client): + try: + + current_price = None + historical_data = None + while current_price is None: + try: + current_price = get_latest_price(ticker) + except Exception as fetch_error: + logging.warning(f"Error fetching price for {ticker}. Retrying... {fetch_error}") + time.sleep(10) + while historical_data is None: + try: + historical_data = get_data(ticker) + except Exception as fetch_error: + logging.warning(f"Error fetching historical data for {ticker}. Retrying... {fetch_error}") + time.sleep(10) + for strategy in strategies: + try: + + db = mongo_client.trading_simulator + holdings_collection = db.algorithm_holdings + print(f"Processing {strategy.__name__} for {ticker}") + strategy_doc = holdings_collection.find_one({"strategy": strategy.__name__}) + if not strategy_doc: + logging.warning(f"Strategy {strategy.__name__} not found in database. Skipping.") + continue -def find_nans_within_rank_holding(): - mongo_client = MongoClient(mongo_url) - db = mongo_client.trading_simulator - collections = db.algorithm_holdings - for strategy in strategies: - strategy_doc = collections.find_one({"strategy": strategy.__name__}) - holdings_doc = strategy_doc.get("holdings", {}) - for ticker in holdings_doc: - if holdings_doc[ticker]['quantity'] == 0: - print(f"{ticker} : {strategy.__name__}") + account_cash = strategy_doc["amount_cash"] + total_portfolio_value = strategy_doc["portfolio_value"] + + portfolio_qty = strategy_doc["holdings"].get(ticker, {}).get("quantity", 0) + simulate_trade(ticker, strategy, historical_data, current_price, + account_cash, portfolio_qty, total_portfolio_value, mongo_client) + except Exception as e: + logging.error(f"Error processing {ticker} for {strategy.__name__}: {e}") + print(f"{ticker} processing completed.") + except Exception as e: + logging.error(f"Error in thread for {ticker}: {e}") -def simulate_trade(ticker, strategy, historical_data, current_price, account_cash, portfolio_qty, total_portfolio_value, mongo_url): +def simulate_trade(ticker, strategy, historical_data, current_price, account_cash, portfolio_qty, total_portfolio_value, mongo_client): """ Simulates a trade based on the given strategy and updates MongoDB. """ # Simulate trading action from strategy print(f"Simulating trade for {ticker} with strategy {strategy.__name__} and quantity of {portfolio_qty}") - action, quantity, _ = strategy(ticker, current_price, historical_data, account_cash, portfolio_qty, total_portfolio_value) + action, quantity = simulate_strategy(strategy, ticker, current_price, historical_data, account_cash, portfolio_qty, total_portfolio_value) # MongoDB setup - client = MongoClient(mongo_url) - db = client.trading_simulator + + db = mongo_client.trading_simulator holdings_collection = db.algorithm_holdings points_collection = db.points_tally @@ -100,7 +127,7 @@ def simulate_trade(ticker, strategy, historical_data, current_price, account_cas # Update holdings and cash based on trade action - if action in ["buy", "strong buy"] and strategy_doc["amount_cash"] - quantity * current_price > 15000 and quantity > 0: + if action in ["buy"] and strategy_doc["amount_cash"] - quantity * current_price > 15000 and quantity > 0 and ((portfolio_qty + quantity) * current_price) / total_portfolio_value < 0.10: logging.info(f"Action: {action} | Ticker: {ticker} | Quantity: {quantity} | Price: {current_price}") # Calculate average price if already holding some shares of the ticker if ticker in holdings_doc: @@ -132,7 +159,7 @@ def simulate_trade(ticker, strategy, historical_data, current_price, account_cas ) - elif action in ["sell", "strong sell"] and str(ticker) in holdings_doc and holdings_doc[str(ticker)]["quantity"] > 0: + elif action in ["sell"] and str(ticker) in holdings_doc and holdings_doc[str(ticker)]["quantity"] > 0: logging.info(f"Action: {action} | Ticker: {ticker} | Quantity: {quantity} | Price: {current_price}") current_qty = holdings_doc[ticker]["quantity"] @@ -220,7 +247,6 @@ def simulate_trade(ticker, strategy, historical_data, current_price, account_cas logging.info(f"Action: {action} | Ticker: {ticker} | Quantity: {quantity} | Price: {current_price}") print(f"Action: {action} | Ticker: {ticker} | Quantity: {quantity} | Price: {current_price}") # Close the MongoDB connection - client.close() def update_portfolio_values(): """ @@ -275,17 +301,17 @@ def update_ranks(): q = [] for strategy_doc in algo_holdings.find({}): """ - based on (points_tally (less points pops first), failed-successful(more neagtive pops first), portfolio value (less value pops first), and then strategy_name), we add to heapq. + based on (points_tally (less points pops first), failed-successful(more negtive pops first), portfolio value (less value pops first), and then strategy_name), we add to heapq. """ strategy_name = strategy_doc["strategy"] if strategy_name == "test" or strategy_name == "test_strategy": continue - heapq.heappush(q, (points_collection.find_one({"strategy": strategy_name})["total_points"]/10 + ((strategy_doc["portfolio_value"] / 50000) * 2), strategy_doc["successful_trades"] - strategy_doc["failed_trades"], strategy_doc["strategy"])) + heapq.heappush(q, (points_collection.find_one({"strategy": strategy_name})["total_points"]/10 + ((strategy_doc["portfolio_value"] / 50000) * 2), strategy_doc["successful_trades"] - strategy_doc["failed_trades"], strategy_doc["amount_cash"], strategy_doc["strategy"])) rank = 1 while q: - _, _, strategy_name = heapq.heappop(q) + _, _, _, strategy_name = heapq.heappop(q) rank_collection.insert_one({"strategy": strategy_name, "rank": rank}) rank+=1 client.close() @@ -297,10 +323,6 @@ def main(): ndaq_tickers = [] early_hour_first_iteration = True post_market_hour_first_iteration = True - data_client = StockHistoricalDataClient(API_KEY, API_SECRET) - mongo_client = MongoClient(mongo_url) - db = mongo_client.trading_simulator - holdings_collection = db.algorithm_holdings while True: @@ -309,60 +331,34 @@ def main(): if status == "open": - logging.info("Market is open. Processing strategies.") - if not ndaq_tickers: - ndaq_tickers = get_ndaq_tickers(mongo_url, FINANCIAL_PREP_API_KEY) - for strategy in strategies: - strategy_doc = holdings_collection.find_one({"strategy": strategy.__name__}) - if not strategy_doc: - logging.warning(f"Strategy {strategy.__name__} not found in database. Skipping.") - continue - - account_cash = strategy_doc["amount_cash"] - total_portfolio_value = strategy_doc["portfolio_value"] - - for ticker in ndaq_tickers: - try: - current_price = None - while current_price is None: - try: - current_price = get_latest_price(ticker) - except: - print(f"Error fetching price for {ticker}. Retrying...") - print(f"Current price of {ticker}: {current_price}") - if current_price is None: - logging.warning(f"Could not fetch price for {ticker}. Skipping.") - continue - - historical_data = trading_strategies.get_historical_data(ticker, data_client) - portfolio_qty = strategy_doc["holdings"].get(ticker, 0) - if portfolio_qty: - portfolio_qty = portfolio_qty["quantity"] - - - simulate_trade(ticker, strategy, historical_data, current_price, - account_cash, portfolio_qty, total_portfolio_value, mongo_url) - - if mongo_client.market_data.market_status.find_one({})["market_status"] == "closed": - break - except Exception as e: - logging.error(f"Error processing {ticker} for {strategy.__name__}: {e}") - if mongo_client.market_data.market_status.find_one({})["market_status"] == "closed": - break - print(f"{strategy} completed") - update_portfolio_values() - - logging.info("Finished processing all strategies. Waiting for 60 seconds.") - time.sleep(600) - + logging.info("Market is open. Processing strategies.") + if not ndaq_tickers: + ndaq_tickers = get_ndaq_tickers(mongo_url, FINANCIAL_PREP_API_KEY) + + threads = [] + + for ticker in ndaq_tickers: + thread = threading.Thread(target=process_ticker, args=(ticker, mongo_client)) + threads.append(thread) + thread.start() + + # Wait for all threads to complete + for thread in threads: + thread.join() + + + update_portfolio_values() + logging.info("Finished processing all strategies. Waiting for 60 seconds.") + time.sleep(60) + elif status == "early_hours": - if early_hour_first_iteration: - - ndaq_tickers = get_ndaq_tickers(mongo_url, FINANCIAL_PREP_API_KEY) - early_hour_first_iteration = False - post_market_hour_first_iteration = True - logging.info("Market is in early hours. Waiting for 60 seconds.") - time.sleep(60) + if early_hour_first_iteration: + + ndaq_tickers = get_ndaq_tickers(mongo_url, FINANCIAL_PREP_API_KEY) + early_hour_first_iteration = False + post_market_hour_first_iteration = True + logging.info("Market is in early hours. Waiting for 60 seconds.") + time.sleep(60) elif status == "closed": @@ -382,7 +378,8 @@ def main(): time.sleep(60) else: logging.error("An error occurred while checking market status.") - time.sleep(60) + time.sleep(60) + mongo_client.close() if __name__ == "__main__": diff --git a/requirements.txt b/requirements.txt index 9f11490..9c95a85 100644 --- a/requirements.txt +++ b/requirements.txt @@ -13,4 +13,6 @@ python-dotenv stats PyWavelets ripser -datetime \ No newline at end of file +datetime +ta-lib-python +pandas-ta \ No newline at end of file diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..7d0a75b --- /dev/null +++ b/setup.py @@ -0,0 +1,132 @@ +from config import API_KEY, API_SECRET, POLYGON_API_KEY, RANK_POLYGON_API_KEY, MONGO_DB_USER, MONGO_DB_PASS, mongo_url +from helper_files.client_helper import strategies +from pymongo import MongoClient +from datetime import datetime +import math +import yfinance as yf +from helper_files.client_helper import get_latest_price +from alpaca.trading.client import TradingClient + +def insert_rank_to_coefficient(i): + try: + client = MongoClient(mongo_url) + db = client.trading_simulator + collections = db.rank_to_coefficient + """ + clear all collections entry first and then insert from 1 to i + """ + collections.delete_many({}) + for i in range(1, i + 1): + + e = math.e + rate = (e**e)/(e**2) - 1 + coefficient = rate**(2 * i) + collections.insert_one( + {"rank": i, + "coefficient": coefficient + } + ) + client.close() + print("Successfully inserted rank to coefficient") + except Exception as exception: + print(exception) + + +def initialize_rank(): + try: + client = MongoClient(mongo_url) + db = client.trading_simulator + collections = db.algorithm_holdings + + initialization_date = datetime.now() + + + for strategy in strategies: + strategy_name = strategy.__name__ + + + collections = db.algorithm_holdings + + if not collections.find_one({"strategy": strategy_name}): + + collections.insert_one({ + "strategy": strategy_name, + "holdings": {}, + "amount_cash": 50000, + "initialized_date": initialization_date, + "total_trades": 0, + "successful_trades": 0, + "neutral_trades": 0, + "failed_trades": 0, + "last_updated": initialization_date, + "portfolio_value": 50000 + }) + + collections = db.points_tally + collections.insert_one({ + "strategy": strategy_name, + "total_points": 0, + "initialized_date": initialization_date, + "last_updated": initialization_date + }) + + + client.close() + print("Successfully initialized rank") + except Exception as exception: + print(exception) + +def initialize_time_delta(): + try: + client = MongoClient(mongo_url) + db = client.trading_simulator + collection = db.time_delta + collection.insert_one({"time_delta": 0.01}) + client.close() + print("Successfully initialized time delta") + except Exception as exception: + print(exception) + +def initialize_market_setup(): + try: + client = MongoClient(mongo_url) + db = client.market_data + collection = db.market_status + collection.insert_one({"market_status": "closed"}) + client.close() + print("Successfully initialized market setup") + except Exception as exception: + print(exception) + +def initialize_portfolio_percentages(): + try: + client = MongoClient(mongo_url) + trading_client = TradingClient(API_KEY, API_SECRET) + account = trading_client.get_account() + db = client.trades + collection = db.portfolio_values + portfolio_value = float(account.portfolio_value) + collection.insert_one({ + "name" : "portfolio_percentage", + "portfolio_value": (portfolio_value-50000)/50000, + }) + collection.insert_one({ + "name" : "ndaq_percentage", + "portfolio_value": (get_latest_price('QQQ')-503.17)/503.17, + }) + collection.insert_one({ + "name" : "spy_percentage", + "portfolio_value": (get_latest_price('SPY')-403.17)/403.17, + }) + client.close() + print("Successfully initialized portfolio percentages") + except Exception as exception: + print(exception) + + +if __name__ == "__main__": + insert_rank_to_coefficient(200) + initialize_rank() + initialize_time_delta() + initialize_market_setup() + initialize_portfolio_percentages() \ No newline at end of file diff --git a/strategies/trading_strategies_v1.py b/strategies/archived_strategies/trading_strategies_v1.py similarity index 98% rename from strategies/trading_strategies_v1.py rename to strategies/archived_strategies/trading_strategies_v1.py index c8e2a92..16ccb5b 100644 --- a/strategies/trading_strategies_v1.py +++ b/strategies/archived_strategies/trading_strategies_v1.py @@ -7,7 +7,8 @@ import numpy as np import pandas as pd -#V2 is now available so please use those methods instead. +#12/7/2024 talib is now available so please use those functions. This file is no longer in use + def get_historical_data(ticker, client, days=100): """ Fetch historical bar data for a given stock ticker. diff --git a/strategies/trading_strategies_v2.py b/strategies/archived_strategies/trading_strategies_v2.py similarity index 99% rename from strategies/trading_strategies_v2.py rename to strategies/archived_strategies/trading_strategies_v2.py index 92d1e8f..48b856b 100644 --- a/strategies/trading_strategies_v2.py +++ b/strategies/archived_strategies/trading_strategies_v2.py @@ -13,6 +13,7 @@ from scipy.spatial.distance import pdist, squareform from scipy.special import zeta # For Riemann zeta function +#12/7/2024 talib is now available so please use those functions. This file is no longer in use # Function to fetch historical bar data using Alpaca StockHistoricalDataClient def get_historical_data(ticker, client, days=100): diff --git a/strategies/trading_strategies_v2_1.py b/strategies/archived_strategies/trading_strategies_v2_1.py similarity index 99% rename from strategies/trading_strategies_v2_1.py rename to strategies/archived_strategies/trading_strategies_v2_1.py index 6345ab7..c7fe8e0 100644 --- a/strategies/trading_strategies_v2_1.py +++ b/strategies/archived_strategies/trading_strategies_v2_1.py @@ -13,6 +13,8 @@ from scipy.spatial.distance import pdist, squareform from scipy.special import zeta # For Riemann zeta function +#12/7/2024 talib is now available so please use those functions. This file is no longer in use + def pairs_trading_strategy(ticker, current_price, historical_data, account_cash, portfolio_qty, total_portfolio_value): """ Pairs Trading Strategy using correlation and z-score diff --git a/strategies/talib_indicators.py b/strategies/talib_indicators.py new file mode 100644 index 0000000..2e37f51 --- /dev/null +++ b/strategies/talib_indicators.py @@ -0,0 +1,1541 @@ +import yfinance as yf +import talib as ta +import numpy as np + +def get_data(ticker, period='max'): + """Retrieve historical data for a given ticker.""" + ticker = yf.Ticker(ticker) + data = ticker.history(period=period) + return data + +def simulate_strategy(strategy, ticker, current_price, historical_data, account_cash, portfolio_qty, total_portfolio_value): + max_investment = total_portfolio_value * 0.10 + action = strategy(ticker, historical_data) + + if action == 'Buy': + return 'buy', min(int(max_investment // current_price), int(account_cash // current_price)) + elif action == 'Sell' and portfolio_qty > 0: + return 'sell', min(portfolio_qty, max(1, int(portfolio_qty * 0.5))) + else: + return 'hold', 0 + +# Overlap Studies + +def BBANDS_indicator(ticker, data): + """Bollinger Bands (BBANDS) indicator.""" + + upper, middle, lower = ta.BBANDS(data['Close'], timeperiod=20) + if data['Close'].iloc[-1] > upper.iloc[-1]: + return 'Sell' + elif data['Close'].iloc[-1] < lower.iloc[-1]: + return 'Buy' + else: + return 'Hold' + +def DEMA_indicator(ticker, data): + """Double Exponential Moving Average (DEMA) indicator.""" + + dema = ta.DEMA(data['Close'], timeperiod=30) + if data['Close'].iloc[-1] > dema.iloc[-1]: + return 'Buy' + elif data['Close'].iloc[-1] < dema.iloc[-1]: + return 'Sell' + else: + return 'Hold' + +def EMA_indicator(ticker, data): + """Exponential Moving Average (EMA) indicator.""" + + ema = ta.EMA(data['Close'], timeperiod=30) + if data['Close'].iloc[-1] > ema.iloc[-1]: + return 'Buy' + elif data['Close'].iloc[-1] < ema.iloc[-1]: + return 'Sell' + else: + return 'Hold' + +def HT_TRENDLINE_indicator(ticker, data): + """Hilbert Transform - Instantaneous Trendline (HT_TRENDLINE) indicator.""" + + ht_trendline = ta.HT_TRENDLINE(data['Close']) + if data['Close'].iloc[-1] > ht_trendline.iloc[-1]: + return 'Buy' + elif data['Close'].iloc[-1] < ht_trendline.iloc[-1]: + return 'Sell' + else: + return 'Hold' + +def KAMA_indicator(ticker, data): + """Kaufman Adaptive Moving Average (KAMA) indicator.""" + + kama = ta.KAMA(data['Close'], timeperiod=30) + if data['Close'].iloc[-1] > kama.iloc[-1]: + return 'Buy' + elif data['Close'].iloc[-1] < kama.iloc[-1]: + return 'Sell' + else: + return 'Hold' + +def MA_indicator(ticker, data): + """Moving average (MA) indicator.""" + + ma = ta.MA(data['Close'], timeperiod=30, matype=0) + if data['Close'].iloc[-1] > ma.iloc[-1]: + return 'Buy' + elif data['Close'].iloc[-1] < ma.iloc[-1]: + return 'Sell' + else: + return 'Hold' + +def MAMA_indicator(ticker, data): + """ + MESA Adaptive Moving Average (MAMA) indicator. + + Parameters: + - ticker (str): Stock ticker symbol. + + Returns: + - str: 'Buy', 'Sell', or 'Hold'. + """ + + close_prices = data['Close'].values + + # Validate enough data + if len(close_prices) < 32: # Minimum length required by MAMA + raise ValueError("Not enough data to compute MAMA.") + + # Calculate MAMA and FAMA + try: + mama, fama = ta.MAMA(close_prices, fastlimit=0.5, slowlimit=0.05) + except Exception as e: + raise RuntimeError(f"Error computing MAMA for {ticker}: {e}") + + # Current price and last computed MAMA + current_price = close_prices[-1] + current_mama = mama[-1] + + # Generate signal + if current_price > current_mama: + return "Buy" + elif current_price < current_mama: + return "Sell" + else: + return "Hold" + +def MAVP_indicator(ticker, data): + """ + Moving Average with Variable Period (MAVP) indicator. + + Parameters: + - ticker (str): Stock ticker symbol. + + Returns: + - str: 'Buy', 'Sell', or 'Hold'. + """ + + close_prices = data['Close'].values + + # Validate enough data + if len(close_prices) < 30: # Ensure enough data for MAVP calculation + raise ValueError("Not enough data to compute MAVP.") + + # Define variable periods as a NumPy array + variable_periods = np.full(len(close_prices), 30, dtype=np.float64) + # Calculate MAVP + try: + mavp = ta.MAVP(close_prices, periods=variable_periods) + except Exception as e: + raise RuntimeError(f"Error computing MAVP for {ticker}: {e}") + + # Current price and last computed MAVP + current_price = close_prices[-1] + current_mavp = mavp[-1] + + # Generate signal + if current_price > current_mavp: + return "Buy" + elif current_price < current_mavp: + return "Sell" + else: + return "Hold" + + +def MIDPOINT_indicator(ticker, data): + """MidPoint over period (MIDPOINT) indicator.""" + + midpoint = ta.MIDPOINT(data['Close'], timeperiod=14) + if data['Close'].iloc[-1] > midpoint.iloc[-1]: + return 'Buy' + elif data['Close'].iloc[-1] < midpoint.iloc[-1]: + return 'Sell' + else: + return 'Hold' + +def MIDPRICE_indicator(ticker, data): + """Midpoint Price over period (MIDPRICE) indicator.""" + + midprice = ta.MIDPRICE(data['High'], data['Low'], timeperiod=14) + if data['Close'].iloc[-1] > midprice.iloc[-1]: + return 'Buy' + elif data['Close'].iloc[-1] < midprice.iloc[-1]: + return 'Sell' + else: + return 'Hold' + +def SAR_indicator(ticker, data): + """Parabolic SAR (SAR) indicator.""" + + sar = ta.SAR(data['High'], data['Low'], acceleration=0, maximum=0) + if data['Close'].iloc[-1] > sar.iloc[-1]: + return 'Buy' + elif data['Close'].iloc[-1] < sar.iloc[-1]: + return 'Sell' + else: + return 'Hold' + +def SAREXT_indicator(ticker, data): + """Parabolic SAR - Extended (SAREXT) indicator.""" + + sarext = ta.SAREXT(data['High'], data['Low'], startvalue=0, offsetonreverse=0, accelerationinitlong=0, accelerationlong=0, accelerationmaxlong=0, accelerationinitshort=0, accelerationshort=0, accelerationmaxshort=0) + if data['Close'].iloc[-1] > sarext.iloc[-1]: + return 'Buy' + elif data['Close'].iloc[-1] < sarext.iloc[-1]: + return 'Sell' + else: + return 'Hold' + +def SMA_indicator(ticker, data): + """Simple Moving Average (SMA) indicator.""" + + sma = ta.SMA(data['Close'], timeperiod=30) + if data['Close'].iloc[-1] > sma.iloc[-1]: + return 'Buy' + elif data['Close'].iloc[-1] < sma.iloc[-1]: + return 'Sell' + else: + return 'Hold' + +def T3_indicator(ticker, data): + """Triple Exponential Moving Average (T3) indicator.""" + + t3 = ta.T3(data['Close'], timeperiod=30, vfactor=0) + if data['Close'].iloc[-1] > t3.iloc[-1]: + return 'Buy' + elif data['Close'].iloc[-1] < t3.iloc[-1]: + return 'Sell' + else: + return 'Hold' + +def TEMA_indicator(ticker, data): + """Triple Exponential Moving Average (TEMA) indicator.""" + + tema = ta.TEMA(data['Close'], timeperiod=30) + if data['Close'].iloc[-1] > tema.iloc[-1]: + return 'Buy' + elif data['Close'].iloc[-1] < tema.iloc[-1]: + return 'Sell' + else: + return 'Hold' + +def TRIMA_indicator(ticker, data): + """Triangular Moving Average (TRIMA) indicator.""" + + trima = ta.TRIMA(data['Close'], timeperiod=30) + if data['Close'].iloc[-1] > trima.iloc[-1]: + return 'Buy' + elif data['Close'].iloc[-1] < trima.iloc[-1]: + return 'Sell' + else: + return 'Hold' + +def WMA_indicator(ticker, data): + """Weighted Moving Average (WMA) indicator.""" + + wma = ta.WMA(data['Close'], timeperiod=30) + if data['Close'].iloc[-1] > wma.iloc[-1]: + return 'Buy' + elif data['Close'].iloc[-1] < wma.iloc[-1]: + return 'Sell' + else: + return 'Hold' + +# Momentum Indicators + +def ADX_indicator(ticker, data): + """Average Directional Movement Index (ADX) indicator.""" + + adx = ta.ADX(data['High'], data['Low'], data['Close'], timeperiod=14) + if adx.iloc[-1] > 25: + return 'Buy' + elif adx.iloc[-1] < 20: + return 'Sell' + else: + return 'Hold' + +def ADXR_indicator(ticker, data): + """Average Directional Movement Index Rating (ADXR) indicator.""" + + adxr = ta.ADXR(data['High'], data['Low'], data['Close'], timeperiod=14) + if adxr.iloc[-1] > 25: + return 'Buy' + elif adxr.iloc[-1] < 20: + return 'Sell' + else: + return 'Hold' + +def APO_indicator(ticker, data): + """Absolute Price Oscillator (APO) indicator.""" + + apo = ta.APO(data['Close'], fastperiod=12, slowperiod=26, matype=0) + if apo.iloc[-1] > 0: + return 'Buy' + elif apo.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def AROON_indicator(ticker, data): + """Aroon (AROON) indicator.""" + + aroon_down, aroon_up = ta.AROON(data['High'], data['Low'], timeperiod=14) + if aroon_up.iloc[-1] > 70: + return 'Buy' + elif aroon_down.iloc[-1] > 70: + return 'Sell' + else: + return 'Hold' + +def AROONOSC_indicator(ticker, data): + """Aroon Oscillator (AROONOSC) indicator.""" + + aroonosc = ta.AROONOSC(data['High'], data['Low'], timeperiod=14) + if aroonosc.iloc[-1] > 0: + return 'Buy' + elif aroonosc.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def BOP_indicator(ticker, data): + """Balance Of Power (BOP) indicator.""" + + bop = ta.BOP(data['Open'], data['High'], data['Low'], data['Close']) + if bop.iloc[-1] > 0: + return 'Buy' + elif bop.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CCI_indicator(ticker, data): + """Commodity Channel Index (CCI) indicator.""" + + cci = ta.CCI(data['High'], data['Low'], data['Close'], timeperiod=14) + if cci.iloc[-1] > 100: + return 'Buy' + elif cci.iloc[-1] < -100: + return 'Sell' + else: + return 'Hold' + +def CMO_indicator(ticker, data): + """Chande Momentum Oscillator (CMO) indicator.""" + + cmo = ta.CMO(data['Close'], timeperiod=14) + if cmo.iloc[-1] > 50: + return 'Buy' + elif cmo.iloc[-1] < -50: + return 'Sell' + else: + return 'Hold' + +def DX_indicator(ticker, data): + """Directional Movement Index (DX) indicator.""" + + dx = ta.DX(data['High'], data['Low'], data['Close'], timeperiod=14) + if dx.iloc[-1] > 25: + return 'Buy' + elif dx.iloc[-1] < 20: + return 'Sell' + else: + return 'Hold' + +def MACD_indicator(ticker, data): + """Moving Average Convergence/Divergence (MACD) indicator.""" + + macd, macdsignal, macdhist = ta.MACD(data['Close'], fastperiod=12, slowperiod=26, signalperiod=9) + if macdhist.iloc[-1] > 0: + return 'Buy' + elif macdhist.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def MACDEXT_indicator(ticker, data): + """MACD with controllable MA type (MACDEXT) indicator.""" + + macd, macdsignal, macdhist = ta.MACDEXT(data['Close'], fastperiod=12, fastmatype=0, slowperiod=26, slowmatype=0, signalperiod=9, signalmatype=0) + if macdhist.iloc[-1] > 0: + return 'Buy' + elif macdhist.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def MACDFIX_indicator(ticker, data): + """Moving Average Convergence/Divergence Fix 12/26 (MACDFIX) indicator.""" + + macd, macdsignal, macdhist = ta.MACDFIX(data['Close'], signalperiod=9) + if macdhist.iloc[-1] > 0: + return 'Buy' + elif macdhist.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def MFI_indicator(ticker, data): + """Money Flow Index (MFI) indicator.""" + + mfi = ta.MFI(data['High'], data['Low'], data['Close'], data['Volume'], timeperiod=14) + if mfi.iloc[-1] > 80: + return 'Sell' + elif mfi.iloc[-1] < 20: + return 'Buy' + else: + return 'Hold' + +def MINUS_DI_indicator(ticker, data): + """Minus Directional Indicator (MINUS_DI) indicator.""" + + minus_di = ta.MINUS_DI(data['High'], data['Low'], data['Close'], timeperiod=14) + if minus_di.iloc[-1] > 25: + return 'Sell' + elif minus_di.iloc[-1] < 20: + return 'Buy' + else: + return 'Hold' + +def MINUS_DM_indicator(ticker, data): + """Minus Directional Movement (MINUS_DM) indicator.""" + + minus_dm = ta.MINUS_DM(data['High'], data['Low'], timeperiod=14) + if minus_dm.iloc[-1] > 0: + return 'Sell' + elif minus_dm.iloc[-1] < 0: + return 'Buy' + else: + return 'Hold' + +def MOM_indicator(ticker, data): + """Momentum (MOM) indicator.""" + + mom = ta.MOM(data['Close'], timeperiod=10) + if mom.iloc[-1] > 0: + return 'Buy' + elif mom.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def PLUS_DI_indicator(ticker, data): + """Plus Directional Indicator (PLUS_DI) indicator.""" + + plus_di = ta.PLUS_DI(data['High'], data['Low'], data['Close'], timeperiod=14) + if plus_di.iloc[-1] > 25: + return 'Buy' + elif plus_di.iloc[-1] < 20: + return 'Sell' + else: + return 'Hold' + +def PLUS_DM_indicator(ticker, data): + """Plus Directional Movement (PLUS_DM) indicator.""" + + plus_dm = ta.PLUS_DM(data['High'], data['Low'], timeperiod=14) + if plus_dm.iloc[-1] > 0: + return 'Buy' + elif plus_dm.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def PPO_indicator(ticker, data): + """Percentage Price Oscillator (PPO) indicator.""" + + ppo = ta.PPO(data['Close'], fastperiod=12, slowperiod=26, matype=0) + if ppo.iloc[-1] > 0: + return 'Buy' + elif ppo.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def ROC_indicator(ticker, data): + """Rate of change : ((price/prevPrice)-1)*100 (ROC) indicator.""" + + roc = ta.ROC(data['Close'], timeperiod=10) + if roc.iloc[-1] > 0: + return 'Buy' + elif roc.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def ROCP_indicator(ticker, data): + """Rate of change Percentage: (price-prevPrice)/prevPrice (ROCP) indicator.""" + + rocp = ta.ROCP(data['Close'], timeperiod=10) + if rocp.iloc[-1] > 0: + return 'Buy' + elif rocp.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def ROCR_indicator(ticker, data): + """Rate of change ratio: (price/prevPrice) (ROCR) indicator.""" + + rocr = ta.ROCR(data['Close'], timeperiod=10) + if rocr.iloc[-1] > 1: + return 'Buy' + elif rocr.iloc[-1] < 1: + return 'Sell' + else: + return 'Hold' + +def ROCR100_indicator(ticker, data): + """Rate of change ratio 100 scale: (price/prevPrice)*100 (ROCR100) indicator.""" + + rocr100 = ta.ROCR100(data['Close'], timeperiod=10) + if rocr100.iloc[-1] > 100: + return 'Buy' + elif rocr100.iloc[-1] < 100: + return 'Sell' + else: + return 'Hold' + +def RSI_indicator(ticker, data): + """Relative Strength Index (RSI) indicator.""" + + rsi = ta.RSI(data['Close'], timeperiod=14) + if rsi.iloc[-1] > 70: + return 'Sell' + elif rsi.iloc[-1] < 30: + return 'Buy' + else: + return 'Hold' + +def STOCH_indicator(ticker, data): + """Stochastic (STOCH) indicator.""" + + slowk, slowd = ta.STOCH(data['High'], data['Low'], data['Close'], fastk_period=5, slowk_period=3, slowk_matype=0, slowd_period=3, slowd_matype=0) + if slowk.iloc[-1] > 80: + return 'Sell' + elif slowk.iloc[-1] < 20: + return 'Buy' + else: + return 'Hold' + +def STOCHF_indicator(ticker, data): + """Stochastic Fast (STOCHF) indicator.""" + + fastk, fastd = ta.STOCHF(data['High'], data['Low'], data['Close'], fastk_period=5, fastd_period=3, fastd_matype=0) + if fastk.iloc[-1] > 80: + return 'Sell' + elif fastk.iloc[-1] < 20: + return 'Buy' + else: + return 'Hold' + +def STOCHRSI_indicator(ticker, data): + """Stochastic Relative Strength Index (STOCHRSI) indicator.""" + + fastk, fastd = ta.STOCHRSI(data['Close'], timeperiod=14, fastk_period=5, fastd_period=3, fastd_matype=0) + if fastk.iloc[-1] > 80: + return 'Sell' + elif fastk.iloc[-1] < 20: + return 'Buy' + else: + return 'Hold' + +def TRIX_indicator(ticker, data): + """1-day Rate-Of-Change (ROC) of a Triple Smooth EMA (TRIX) indicator.""" + + trix = ta.TRIX(data['Close'], timeperiod=30) + if trix.iloc[-1] > 0: + return 'Buy' + elif trix.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def ULTOSC_indicator(ticker, data): + """Ultimate Oscillator (ULTOSC) indicator.""" + + ultosc = ta.ULTOSC(data['High'], data['Low'], data['Close'], timeperiod1=7, timeperiod2=14, timeperiod3=28) + if ultosc.iloc[-1] > 70: + return 'Sell' + elif ultosc.iloc[-1] < 30: + return 'Buy' + else: + return 'Hold' + +def WILLR_indicator(ticker, data): + """Williams' %R (WILLR) indicator.""" + + willr = ta.WILLR(data['High'], data['Low'], data['Close'], timeperiod=14) + if willr.iloc[-1] > -20: + return 'Sell' + elif willr.iloc[-1] < -80: + return 'Buy' + else: + return 'Hold' + +# Volume Indicators + +def AD_indicator(ticker, data): + """Chaikin A/D Line (AD) indicator.""" + + ad = ta.AD(data['High'], data['Low'], data['Close'], data['Volume']) + if ad.iloc[-1] > 0: + return 'Buy' + elif ad.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def ADOSC_indicator(ticker, data): + """Chaikin A/D Oscillator (ADOSC) indicator.""" + + adosc = ta.ADOSC(data['High'], data['Low'], data['Close'], data['Volume'], fastperiod=3, slowperiod=10) + if adosc.iloc[-1] > 0: + return 'Buy' + elif adosc.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def OBV_indicator(ticker, data): + """On Balance Volume (OBV) indicator.""" + + obv = ta.OBV(data['Close'], data['Volume']) + if obv.iloc[-1] > 0: + return 'Buy' + elif obv.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +# Cycle Indicators + +def HT_DCPERIOD_indicator(ticker, data): + """Hilbert Transform - Dominant Cycle Period (HT_DCPERIOD) indicator.""" + + ht_dcperiod = ta.HT_DCPERIOD(data['Close']) + if ht_dcperiod.iloc[-1] > 20: + return 'Buy' + elif ht_dcperiod.iloc[-1] < 10: + return 'Sell' + else: + return 'Hold' + +def HT_DCPHASE_indicator(ticker, data): + """Hilbert Transform - Dominant Cycle Phase (HT_DCPHASE) indicator.""" + + ht_dcphase = ta.HT_DCPHASE(data['Close']) + if ht_dcphase.iloc[-1] > 0: + return 'Buy' + elif ht_dcphase.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def HT_PHASOR_indicator(ticker, data): + """Hilbert Transform - Phasor Components (HT_PHASOR) indicator.""" + + inphase, quadrature = ta.HT_PHASOR(data['Close']) + if inphase.iloc[-1] > 0: + return 'Buy' + elif inphase.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def HT_SINE_indicator(ticker, data): + """Hilbert Transform - SineWave (HT_SINE) indicator.""" + + sine, leadsine = ta.HT_SINE(data['Close']) + if sine.iloc[-1] > 0: + return 'Buy' + elif sine.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def HT_TRENDMODE_indicator(ticker, data): + """Hilbert Transform - Trend vs Cycle Mode (HT_TRENDMODE) indicator.""" + + ht_trendmode = ta.HT_TRENDMODE(data['Close']) + if ht_trendmode.iloc[-1] > 0: + return 'Buy' + elif ht_trendmode.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +# Price Transform + +def AVGPRICE_indicator(ticker, data): + """Average Price (AVGPRICE) indicator.""" + + avgprice = ta.AVGPRICE(data['Open'], data['High'], data['Low'], data['Close']) + if data['Close'].iloc[-1] > avgprice.iloc[-1]: + return 'Buy' + elif data['Close'].iloc[-1] < avgprice.iloc[-1]: + return 'Sell' + else: + return 'Hold' + +def MEDPRICE_indicator(ticker, data): + """Median Price (MEDPRICE) indicator.""" + + medprice = ta.MEDPRICE(data['High'], data['Low']) + if data['Close'].iloc[-1] > medprice.iloc[-1]: + return 'Buy' + elif data['Close'].iloc[-1] < medprice.iloc[-1]: + return 'Sell' + else: + return 'Hold' + +def TYPPRICE_indicator(ticker, data): + """Typical Price (TYPPRICE) indicator.""" + + typprice = ta.TYPPRICE(data['High'], data['Low'], data['Close']) + if data['Close'].iloc[-1] > typprice.iloc[-1]: + return 'Buy' + elif data['Close'].iloc[-1] < typprice.iloc[-1]: + return 'Sell' + else: + return 'Hold' + +def WCLPRICE_indicator(ticker, data): + """Weighted Close Price (WCLPRICE) indicator.""" + + wclprice = ta.WCLPRICE(data['High'], data['Low'], data['Close']) + if data['Close'].iloc[-1] > wclprice.iloc[-1]: + return 'Buy' + elif data['Close'].iloc[-1] < wclprice.iloc[-1]: + return 'Sell' + else: + return 'Hold' + +# Volatility Indicators + +def ATR_indicator(ticker, data): + """Average True Range (ATR) indicator.""" + + atr = ta.ATR(data['High'], data['Low'], data['Close'], timeperiod=14) + if atr.iloc[-1] > 20: + return 'Buy' + elif atr.iloc[-1] < 10: + return 'Sell' + else: + return 'Hold' + +def NATR_indicator(ticker, data): + """Normalized Average True Range (NATR) indicator.""" + + natr = ta.NATR(data['High'], data['Low'], data['Close'], timeperiod=14) + if natr.iloc[-1] > 20: + return 'Buy' + elif natr.iloc[-1] < 10: + return 'Sell' + else: + return 'Hold' + +def TRANGE_indicator(ticker, data): + """True Range (TRANGE) indicator.""" + + trange = ta.TRANGE(data['High'], data['Low'], data['Close']) + if trange.iloc[-1] > 20: + return 'Buy' + elif trange.iloc[-1] < 10: + return 'Sell' + else: + return 'Hold' + +# Pattern Recognition + +def CDL2CROWS_indicator(ticker, data): + """Two Crows (CDL2CROWS) indicator.""" + + cdl2crows = ta.CDL2CROWS(data['Open'], data['High'], data['Low'], data['Close']) + if cdl2crows.iloc[-1] > 0: + return 'Buy' + elif cdl2crows.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDL3BLACKCROWS_indicator(ticker, data): + """Three Black Crows (CDL3BLACKCROWS) indicator.""" + + cdl3blackcrows = ta.CDL3BLACKCROWS(data['Open'], data['High'], data['Low'], data['Close']) + if cdl3blackcrows.iloc[-1] > 0: + return 'Buy' + elif cdl3blackcrows.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDL3INSIDE_indicator(ticker, data): + """Three Inside Up/Down (CDL3INSIDE) indicator.""" + + cdl3inside = ta.CDL3INSIDE(data['Open'], data['High'], data['Low'], data['Close']) + if cdl3inside.iloc[-1] > 0: + return 'Buy' + elif cdl3inside.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDL3LINESTRIKE_indicator(ticker, data): + """Three-Line Strike (CDL3LINESTRIKE) indicator.""" + + cdl3linestrike = ta.CDL3LINESTRIKE(data['Open'], data['High'], data['Low'], data['Close']) + if cdl3linestrike.iloc[-1] > 0: + return 'Buy' + elif cdl3linestrike.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDL3OUTSIDE_indicator(ticker, data): + """Three Outside Up/Down (CDL3OUTSIDE) indicator.""" + + cdl3outside = ta.CDL3OUTSIDE(data['Open'], data['High'], data['Low'], data['Close']) + if cdl3outside.iloc[-1] > 0: + return 'Buy' + elif cdl3outside.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDL3STARSINSOUTH_indicator(ticker, data): + """Three Stars In The South (CDL3STARSINSOUTH) indicator.""" + + cdl3starsinsouth = ta.CDL3STARSINSOUTH(data['Open'], data['High'], data['Low'], data['Close']) + if cdl3starsinsouth.iloc[-1] > 0: + return 'Buy' + elif cdl3starsinsouth.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDL3WHITESOLDIERS_indicator(ticker, data): + """Three Advancing White Soldiers (CDL3WHITESOLDIERS) indicator.""" + + cdl3whitesoldiers = ta.CDL3WHITESOLDIERS(data['Open'], data['High'], data['Low'], data['Close']) + if cdl3whitesoldiers.iloc[-1] > 0: + return 'Buy' + elif cdl3whitesoldiers.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDLABANDONEDBABY_indicator(ticker, data): + """Abandoned Baby (CDLABANDONEDBABY) indicator.""" + + cdlabandonedbaby = ta.CDLABANDONEDBABY(data['Open'], data['High'], data['Low'], data['Close'], penetration=0) + if cdlabandonedbaby.iloc[-1] > 0: + return 'Buy' + elif cdlabandonedbaby.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDLADVANCEBLOCK_indicator(ticker, data): + """Advance Block (CDLADVANCEBLOCK) indicator.""" + + cdladvanceblock = ta.CDLADVANCEBLOCK(data['Open'], data['High'], data['Low'], data['Close']) + if cdladvanceblock.iloc[-1] > 0: + return 'Buy' + elif cdladvanceblock.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDLBELTHOLD_indicator(ticker, data): + """Belt-hold (CDLBELTHOLD) indicator.""" + + cdlbelthold = ta.CDLBELTHOLD(data['Open'], data['High'], data['Low'], data['Close']) + if cdlbelthold.iloc[-1] > 0: + return 'Buy' + elif cdlbelthold.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDLBREAKAWAY_indicator(ticker, data): + """Breakaway (CDLBREAKAWAY) indicator.""" + + cdlbreakaway = ta.CDLBREAKAWAY(data['Open'], data['High'], data['Low'], data['Close']) + if cdlbreakaway.iloc[-1] > 0: + return 'Buy' + elif cdlbreakaway.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDLCLOSINGMARUBOZU_indicator(ticker, data): + """Closing Marubozu (CDLCLOSINGMARUBOZU) indicator.""" + + cdlclosingmarubozu = ta.CDLCLOSINGMARUBOZU(data['Open'], data['High'], data['Low'], data['Close']) + if cdlclosingmarubozu.iloc[-1] > 0: + return 'Buy' + elif cdlclosingmarubozu.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDLCONCEALBABYSWALL_indicator(ticker, data): + """Concealing Baby Swallow (CDLCONCEALBABYSWALL) indicator.""" + + cdlconcealbabyswall = ta.CDLCONCEALBABYSWALL(data['Open'], data['High'], data['Low'], data['Close']) + if cdlconcealbabyswall.iloc[-1] > 0: + return 'Buy' + elif cdlconcealbabyswall.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDLCOUNTERATTACK_indicator(ticker, data): + """Counterattack (CDLCOUNTERATTACK) indicator.""" + + cdlcounterattack = ta.CDLCOUNTERATTACK(data['Open'], data['High'], data['Low'], data['Close']) + if cdlcounterattack.iloc[-1] > 0: + return 'Buy' + elif cdlcounterattack.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDLDARKCLOUDCOVER_indicator(ticker, data): + """Dark Cloud Cover (CDLDARKCLOUDCOVER) indicator.""" + + cdldarkcloudcover = ta.CDLDARKCLOUDCOVER(data['Open'], data['High'], data['Low'], data['Close'], penetration=0) + if cdldarkcloudcover.iloc[-1] > 0: + return 'Buy' + elif cdldarkcloudcover.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDLDOJI_indicator(ticker, data): + """Doji (CDLDOJI) indicator.""" + + cdldoji = ta.CDLDOJI(data['Open'], data['High'], data['Low'], data['Close']) + if cdldoji.iloc[-1] > 0: + return 'Buy' + elif cdldoji.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDLDOJISTAR_indicator(ticker, data): + """Doji Star (CDLDOJISTAR) indicator.""" + + cdldojistar = ta.CDLDOJISTAR(data['Open'], data['High'], data['Low'], data['Close']) + if cdldojistar.iloc[-1] > 0: + return 'Buy' + elif cdldojistar.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDLDRAGONFLYDOJI_indicator(ticker, data): + """Dragonfly Doji (CDLDRAGONFLYDOJI) indicator.""" + + cdldragonflydoji = ta.CDLDRAGONFLYDOJI(data['Open'], data['High'], data['Low'], data['Close']) + if cdldragonflydoji.iloc[-1] > 0: + return 'Buy' + elif cdldragonflydoji.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDLENGULFING_indicator(ticker, data): + """Engulfing Pattern (CDLENGULFING) indicator.""" + + cdlengulfing = ta.CDLENGULFING(data['Open'], data['High'], data['Low'], data['Close']) + if cdlengulfing.iloc[-1] > 0: + return 'Buy' + elif cdlengulfing.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDLEVENINGDOJISTAR_indicator(ticker, data): + """Evening Doji Star (CDLEVENINGDOJISTAR) indicator.""" + + cdlEveningDojiStar = ta.CDLEVENINGDOJISTAR(data['Open'], data['High'], data['Low'], data['Close'], penetration=0) + if cdlEveningDojiStar.iloc[-1] > 0: + return 'Buy' + elif cdlEveningDojiStar.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDLEVENINGSTAR_indicator(ticker, data): + """Evening Star (CDLEVENINGSTAR) indicator.""" + + cdlEveningStar = ta.CDLEVENINGSTAR(data['Open'], data['High'], data['Low'], data['Close'], penetration=0) + if cdlEveningStar.iloc[-1] > 0: + return 'Buy' + elif cdlEveningStar.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDLGAPSIDESIDEWHITE_indicator(ticker, data): + """Up/Down-gap side-by-side white lines (CDLGAPSIDESIDEWHITE) indicator.""" + + cdlgapsidesidewhite = ta.CDLGAPSIDESIDEWHITE(data['Open'], data['High'], data['Low'], data['Close']) + if cdlgapsidesidewhite.iloc[-1] > 0: + return 'Buy' + elif cdlgapsidesidewhite.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDLGRAVESTONEDOJI_indicator(ticker, data): + """Gravestone Doji (CDLGRAVESTONEDOJI) indicator.""" + + cdlgravestonedoji = ta.CDLGRAVESTONEDOJI(data['Open'], data['High'], data['Low'], data['Close']) + if cdlgravestonedoji.iloc[-1] > 0: + return 'Buy' + elif cdlgravestonedoji.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDLHAMMER_indicator(ticker, data): + """Hammer (CDLHAMMER) indicator.""" + + cdlhammer = ta.CDLHAMMER(data['Open'], data['High'], data['Low'], data['Close']) + if cdlhammer.iloc[-1] > 0: + return 'Buy' + elif cdlhammer.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDLHANGINGMAN_indicator(ticker, data): + """Hanging Man (CDLHANGINGMAN) indicator.""" + + cdlhangingman = ta.CDLHANGINGMAN(data['Open'], data['High'], data['Low'], data['Close']) + if cdlhangingman.iloc[-1] > 0: + return 'Buy' + elif cdlhangingman.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDLHARAMI_indicator(ticker, data): + """Harami Pattern (CDLHARAMI) indicator.""" + + cdlharami = ta.CDLHARAMI(data['Open'], data['High'], data['Low'], data['Close']) + if cdlharami.iloc[-1] > 0: + return 'Buy' + elif cdlharami.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDLHARAMICROSS_indicator(ticker, data): + """Harami Cross Pattern (CDLHARAMICROSS) indicator.""" + + cdlharamicross = ta.CDLHARAMICROSS(data['Open'], data['High'], data['Low'], data['Close']) + if cdlharamicross.iloc[-1] > 0: + return 'Buy' + elif cdlharamicross.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDLHIGHWAVE_indicator(ticker, data): + """High-Wave Candle (CDLHIGHWAVE) indicator.""" + + cdlhighwave = ta.CDLHIGHWAVE(data['Open'], data['High'], data['Low'], data['Close']) + if cdlhighwave.iloc[-1] > 0: + return 'Buy' + elif cdlhighwave.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDLHIKKAKE_indicator(ticker, data): + """Hikkake Pattern (CDLHIKKAKE) indicator.""" + + cdlhikkake = ta.CDLHIKKAKE(data['Open'], data['High'], data['Low'], data['Close']) + if cdlhikkake.iloc[-1] > 0: + return 'Buy' + elif cdlhikkake.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDLHIKKAKEMOD_indicator(ticker, data): + """Modified Hikkake Pattern (CDLHIKKAKEMOD) indicator.""" + + cdlhikkakemod = ta.CDLHIKKAKEMOD(data['Open'], data['High'], data['Low'], data['Close']) + if cdlhikkakemod.iloc[-1] > 0: + return 'Buy' + elif cdlhikkakemod.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDLHOMINGPIGEON_indicator(ticker, data): + """Homing Pigeon (CDLHOMINGPIGEON) indicator.""" + + cdlhomingpigeon = ta.CDLHOMINGPIGEON(data['Open'], data['High'], data['Low'], data['Close']) + if cdlhomingpigeon.iloc[-1] > 0: + return 'Buy' + elif cdlhomingpigeon.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDLIDENTICAL3CROWS_indicator(ticker, data): + """Identical Three Crows (CDLIDENTICAL3CROWS) indicator.""" + + cdlidentical3crows = ta.CDLIDENTICAL3CROWS(data['Open'], data['High'], data['Low'], data['Close']) + if cdlidentical3crows.iloc[-1] > 0: + return 'Buy' + elif cdlidentical3crows.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDLINNECK_indicator(ticker, data): + """In-Neck Pattern (CDLINNECK) indicator.""" + + cdlInNeck = ta.CDLINNECK(data['Open'], data['High'], data['Low'], data['Close']) + if cdlInNeck.iloc[-1] > 0: + return 'Buy' + elif cdlInNeck.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDLINVERTEDHAMMER_indicator(ticker, data): + """Inverted Hammer (CDLINVERTEDHAMMER) indicator.""" + + cdlInvertedHammer = ta.CDLINVERTEDHAMMER(data['Open'], data['High'], data['Low'], data['Close']) + if cdlInvertedHammer.iloc[-1] > 0: + return 'Buy' + elif cdlInvertedHammer.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDLKICKING_indicator(ticker, data): + """Kicking (CDLKICKING) indicator.""" + + cdlkicking = ta.CDLKICKING(data['Open'], data['High'], data['Low'], data['Close']) + if cdlkicking.iloc[-1] > 0: + return 'Buy' + elif cdlkicking.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + + +def CDLKICKINGBYLENGTH_indicator(ticker, data): + """Kicking - bull/bear determined by the longer marubozu (CDLKICKINGBYLENGTH) indicator.""" + + cdlkickingbylength = ta.CDLKICKINGBYLENGTH(data['Open'], data['High'], data['Low'], data['Close']) + if cdlkickingbylength.iloc[-1] > 0: + return 'Buy' + elif cdlkickingbylength.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDLLADDERBOTTOM_indicator(ticker, data): + """Ladder Bottom (CDLLADDERBOTTOM) indicator.""" + + cdlladderbottom = ta.CDLLADDERBOTTOM(data['Open'], data['High'], data['Low'], data['Close']) + if cdlladderbottom.iloc[-1] > 0: + return 'Buy' + elif cdlladderbottom.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDLLONGLEGGEDDOJI_indicator(ticker, data): + """Long Legged Doji (CDLLONGLEGGEDDOJI) indicator.""" + + cdllongleggeddoji = ta.CDLLONGLEGGEDDOJI(data['Open'], data['High'], data['Low'], data['Close']) + if cdllongleggeddoji.iloc[-1] > 0: + return 'Buy' + elif cdllongleggeddoji.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDLLONGLINE_indicator(ticker, data): + """Long Line Candle (CDLLONGLINE) indicator.""" + + cdllongline = ta.CDLLONGLINE(data['Open'], data['High'], data['Low'], data['Close']) + if cdllongline.iloc[-1] > 0: + return 'Buy' + elif cdllongline.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDLMARUBOZU_indicator(ticker, data): + """Marubozu (CDLMARUBOZU) indicator.""" + + cdlmarubozu = ta.CDLMARUBOZU(data['Open'], data['High'], data['Low'], data['Close']) + if cdlmarubozu.iloc[-1] > 0: + return 'Buy' + elif cdlmarubozu.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDLMATCHINGLOW_indicator(ticker, data): + """Matching Low (CDLMATCHINGLOW) indicator.""" + + cdlmatchinglow = ta.CDLMATCHINGLOW(data['Open'], data['High'], data['Low'], data['Close']) + if cdlmatchinglow.iloc[-1] > 0: + return 'Buy' + elif cdlmatchinglow.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDLMATHOLD_indicator(ticker, data): + """Mat Hold (CDLMATHOLD) indicator.""" + + cdlmathold = ta.CDLMATHOLD(data['Open'], data['High'], data['Low'], data['Close'], penetration=0) + if cdlmathold.iloc[-1] > 0: + return 'Buy' + elif cdlmathold.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDLMORNINGDOJISTAR_indicator(ticker, data): + """Morning Doji Star (CDLMORNINGDOJISTAR) indicator.""" + + cdlmorningdojistar = ta.CDLMORNINGDOJISTAR(data['Open'], data['High'], data['Low'], data['Close'], penetration=0) + if cdlmorningdojistar.iloc[-1] > 0: + return 'Buy' + elif cdlmorningdojistar.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDLMORNINGSTAR_indicator(ticker, data): + """Morning Star (CDLMORNINGSTAR) indicator.""" + + cdlmorningstar = ta.CDLMORNINGSTAR(data['Open'], data['High'], data['Low'], data['Close'], penetration=0) + if cdlmorningstar.iloc[-1] > 0: + return 'Buy' + elif cdlmorningstar.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDLONNECK_indicator(ticker, data): + """On-Neck Pattern (CDLONNECK) indicator.""" + + cdlonneck = ta.CDLONNECK(data['Open'], data['High'], data['Low'], data['Close']) + if cdlonneck.iloc[-1] > 0: + return 'Buy' + elif cdlonneck.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDLPIERCING_indicator(ticker, data): + """Piercing Pattern (CDLPIERCING) indicator.""" + + cdlpiercing = ta.CDLPIERCING(data['Open'], data['High'], data['Low'], data['Close']) + if cdlpiercing.iloc[-1] > 0: + return 'Buy' + elif cdlpiercing.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDLRICKSHAWMAN_indicator(ticker, data): + """Rickshaw Man (CDLRICKSHAWMAN) indicator.""" + + cdlrickshawman = ta.CDLRICKSHAWMAN(data['Open'], data['High'], data['Low'], data['Close']) + if cdlrickshawman.iloc[-1] > 0: + return 'Buy' + elif cdlrickshawman.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDLRISEFALL3METHODS_indicator(ticker, data): + """Rising/Falling Three Methods (CDLRISEFALL3METHODS) indicator.""" + + cdlrisefall3methods = ta.CDLRISEFALL3METHODS(data['Open'], data['High'], data['Low'], data['Close']) + if cdlrisefall3methods.iloc[-1] > 0: + return 'Buy' + elif cdlrisefall3methods.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDLSEPARATINGLINES_indicator(ticker, data): + """Separating Lines (CDLSEPARATINGLINES) indicator.""" + + cdlseparatinglines = ta.CDLSEPARATINGLINES(data['Open'], data['High'], data['Low'], data['Close']) + if cdlseparatinglines.iloc[-1] > 0: + return 'Buy' + elif cdlseparatinglines.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDLSHOOTINGSTAR_indicator(ticker, data): + """Shooting Star (CDLSHOOTINGSTAR) indicator.""" + + cdlshootingstar = ta.CDLSHOOTINGSTAR(data['Open'], data['High'], data['Low'], data['Close']) + if cdlshootingstar.iloc[-1] > 0: + return 'Buy' + elif cdlshootingstar.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDLSHORTLINE_indicator(ticker, data): + """Short Line Candle (CDLSHORTLINE) indicator.""" + + cdlshortline = ta.CDLSHORTLINE(data['Open'], data['High'], data['Low'], data['Close']) + if cdlshortline.iloc[-1] > 0: + return 'Buy' + elif cdlshortline.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDLSPINNINGTOP_indicator(ticker, data): + """Spinning Top (CDLSPINNINGTOP) indicator.""" + + cdlspinningtop = ta.CDLSPINNINGTOP(data['Open'], data['High'], data['Low'], data['Close']) + if cdlspinningtop.iloc[-1] > 0: + return 'Buy' + elif cdlspinningtop.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDLSTALLEDPATTERN_indicator(ticker, data): + """Stalled Pattern (CDLSTALLEDPATTERN) indicator.""" + + cdlstalledpattern = ta.CDLSTALLEDPATTERN(data['Open'], data['High'], data['Low'], data['Close']) + if cdlstalledpattern.iloc[-1] > 0: + return 'Buy' + elif cdlstalledpattern.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDLSTICKSANDWICH_indicator(ticker, data): + """Stick Sandwich (CDLSTICKSANDWICH) indicator.""" + + cdlsticksandwich = ta.CDLSTICKSANDWICH(data['Open'], data['High'], data['Low'], data['Close']) + if cdlsticksandwich.iloc[-1] > 0: + return 'Buy' + elif cdlsticksandwich.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDLTAKURI_indicator(ticker, data): + """Takuri (Dragonfly Doji with very long lower shadow) (CDLTAKURI) indicator.""" + + cdltakuri = ta.CDLTAKURI(data['Open'], data['High'], data['Low'], data['Close']) + if cdltakuri.iloc[-1] > 0: + return 'Buy' + elif cdltakuri.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDLTASUKIGAP_indicator(ticker, data): + """Tasuki Gap (CDLTASUKIGAP) indicator.""" + + cdltasukigap = ta.CDLTASUKIGAP(data['Open'], data['High'], data['Low'], data['Close']) + if cdltasukigap.iloc[-1] > 0: + return 'Buy' + elif cdltasukigap.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDLTHRUSTING_indicator(ticker, data): + """Thrusting Pattern (CDLTHRUSTING) indicator.""" + + cdlthrusting = ta.CDLTHRUSTING(data['Open'], data['High'], data['Low'], data['Close']) + if cdlthrusting.iloc[-1] > 0: + return 'Buy' + elif cdlthrusting.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDLTRISTAR_indicator(ticker, data): + """Tristar Pattern (CDLTRISTAR) indicator.""" + + cdltristar = ta.CDLTRISTAR(data['Open'], data['High'], data['Low'], data['Close']) + if cdltristar.iloc[-1] > 0: + return 'Buy' + elif cdltristar.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDLUNIQUE3RIVER_indicator(ticker, data): + """Unique 3 River (CDLUNIQUE3RIVER) indicator.""" + + cdlunique3river = ta.CDLUNIQUE3RIVER(data['Open'], data['High'], data['Low'], data['Close']) + if cdlunique3river.iloc[-1] > 0: + return 'Buy' + elif cdlunique3river.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDLUPSIDEGAP2CROWS_indicator(ticker, data): + """Upside Gap Two Crows (CDLUPSIDEGAP2CROWS) indicator.""" + + cdlupsidegap2crows = ta.CDLUPSIDEGAP2CROWS(data['Open'], data['High'], data['Low'], data['Close']) + if cdlupsidegap2crows.iloc[-1] > 0: + return 'Buy' + elif cdlupsidegap2crows.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def CDLXSIDEGAP3METHODS_indicator(ticker, data): + """Upside/Downside Gap Three Methods (CDLXSIDEGAP3METHODS) indicator.""" + + cdlxsidegap3methods = ta.CDLXSIDEGAP3METHODS(data['Open'], data['High'], data['Low'], data['Close']) + if cdlxsidegap3methods.iloc[-1] > 0: + return 'Buy' + elif cdlxsidegap3methods.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +# Statistic Functions + +def BETA_indicator(ticker, data): + """Beta (BETA) indicator.""" + + beta = ta.BETA(data['High'], data['Low'], timeperiod=5) + if beta.iloc[-1] > 1: + return 'Buy' + elif beta.iloc[-1] < 1: + return 'Sell' + else: + return 'Hold' + +def CORREL_indicator(ticker, data): + """Pearson's Correlation Coefficient (r) (CORREL) indicator.""" + + correl = ta.CORREL(data['High'], data['Low'], timeperiod=30) + if correl.iloc[-1] > 0.5: + return 'Buy' + elif correl.iloc[-1] < -0.5: + return 'Sell' + else: + return 'Hold' + +def LINEARREG_indicator(ticker, data): + """Linear Regression (LINEARREG) indicator.""" + + linearreg = ta.LINEARREG(data['Close'], timeperiod=14) + if data['Close'].iloc[-1] > linearreg.iloc[-1]: + return 'Buy' + elif data['Close'].iloc[-1] < linearreg.iloc[-1]: + return 'Sell' + else: + return 'Hold' + +def LINEARREG_ANGLE_indicator(ticker, data): + """Linear Regression Angle (LINEARREG_ANGLE) indicator.""" + + linearreg_angle = ta.LINEARREG_ANGLE(data['Close'], timeperiod=14) + if linearreg_angle.iloc[-1] > 0: + return 'Buy' + elif linearreg_angle.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def LINEARREG_INTERCEPT_indicator(ticker, data): + """Linear Regression Intercept (LINEARREG_INTERCEPT) indicator.""" + + linearreg_intercept = ta.LINEARREG_INTERCEPT(data['Close'], timeperiod=14) + if data['Close'].iloc[-1] > linearreg_intercept.iloc[-1]: + return 'Buy' + elif data['Close'].iloc[-1] < linearreg_intercept.iloc[-1]: + return 'Sell' + else: + return 'Hold' + +def LINEARREG_SLOPE_indicator(ticker, data): + """Linear Regression Slope (LINEARREG_SLOPE) indicator.""" + + linearreg_slope = ta.LINEARREG_SLOPE(data['Close'], timeperiod=14) + if linearreg_slope.iloc[-1] > 0: + return 'Buy' + elif linearreg_slope.iloc[-1] < 0: + return 'Sell' + else: + return 'Hold' + +def STDDEV_indicator(ticker, data): + """Standard Deviation (STDDEV) indicator.""" + + stddev = ta.STDDEV(data['Close'], timeperiod=20, nbdev=1) + if stddev.iloc[-1] > 20: + return 'Buy' + elif stddev.iloc[-1] < 10: + return 'Sell' + else: + return 'Hold' + +def TSF_indicator(ticker, data): + """Time Series Forecast (TSF) indicator.""" + + tsf = ta.TSF(data['Close'], timeperiod=14) + if data['Close'].iloc[-1] > tsf.iloc[-1]: + return 'Buy' + elif data['Close'].iloc[-1] < tsf.iloc[-1]: + return 'Sell' + else: + return 'Hold' + +def VAR_indicator(ticker, data): + """Variance (VAR) indicator.""" + + var = ta.VAR(data['Close'], timeperiod=5, nbdev=1) + if var.iloc[-1] > 20: + return 'Buy' + elif var.iloc[-1] < 10: + return 'Sell' + else: + return 'Hold' + diff --git a/testing_client.py b/testing_client.py index 48c1b88..c73fc3f 100644 --- a/testing_client.py +++ b/testing_client.py @@ -1,39 +1,13 @@ -import pandas as pd -from datetime import datetime, timedelta from alpaca.data.historical import StockHistoricalDataClient -from alpaca.data.requests import StockBarsRequest -from alpaca.data.timeframe import TimeFrame from config import API_KEY, API_SECRET, FINANCIAL_PREP_API_KEY, POLYGON_API_KEY -import strategies.trading_strategies_v2_1 as ts -import helper_files.client_helper from pymongo import MongoClient -import yfinance as yf -from helper_files.client_helper import get_ndaq_tickers, get_latest_price +from helper_files.client_helper import get_ndaq_tickers from config import MONGO_DB_USER, MONGO_DB_PASS -from helper_files.client_helper import get_latest_price -import requests +from helper_files.client_helper import strategies +from strategies.talib_indicators import get_data +import threading mongo_url = f"mongodb+srv://{MONGO_DB_USER}:{MONGO_DB_PASS}@cluster0.0qoxq.mongodb.net" -def get_historical_data(ticker, client, days=100): - """ - Fetch historical bar data for a given stock ticker. - - :param ticker: The stock ticker symbol. - :param client: An instance of StockHistoricalDataClient. - :param days: Number of days of historical data to fetch. - :return: DataFrame with historical stock bar data. test all data for all tickers - try to follow trading client specification - """ - start_time = datetime.now() - timedelta(days=days) - request_params = StockBarsRequest( - symbol_or_symbols=ticker, - timeframe=TimeFrame.Day, - start=start_time - ) - - bars = client.get_stock_bars(request_params) - data = bars.df - return data - def test_strategies(): # Initialize the StockHistoricalDataClient @@ -44,46 +18,17 @@ def test_strategies(): # Define test parameters - for ticker in tickers: - account_cash = 50000 - portfolio_qty = 100 - total_portfolio_value = 2000 - - historical_data = get_historical_data(ticker, client) - current_price = historical_data['close'].iloc[-1] - # Test each strategy - - strategies = [ts.levy_distribution_strategy, ts.regime_switching_strategy] - for strategy in strategies: + for ticker in tickers: + data = get_data(ticker) + for strategy in strategies: + try: - decision, quantity, ticker = strategy( - ticker, - current_price, - historical_data, - account_cash, - portfolio_qty, - total_portfolio_value - ) - - print(f"Strategy {strategy.__name__} recommends {ticker} and {decision} and {quantity}") - + decision = strategy(ticker, data) + print(f"{strategy.__name__} : {decision} :{ticker}") except Exception as e: print(f"ERROR processing {ticker} for {strategy.__name__}: {e}") - - - - - - -def test_helper(): - ticker = 'MSFT' # Replace with your desired ticker - # Initialize the StockHistoricalDataClient - client = StockHistoricalDataClient(API_KEY, API_SECRET) - get_historical_data(ticker, client) - - print(get_latest_price(ticker)) if __name__ == "__main__": - test_helper() \ No newline at end of file + test_strategies() \ No newline at end of file diff --git a/trading_client.py b/trading_client.py index d61e15e..6d46acd 100644 --- a/trading_client.py +++ b/trading_client.py @@ -13,7 +13,7 @@ from alpaca.data.historical.stock import StockHistoricalDataClient from alpaca.trading.requests import MarketOrderRequest from alpaca.trading.enums import OrderSide, TimeInForce -from strategies.trading_strategies_v1 import get_historical_data +from strategies.archived_strategies.trading_strategies_v1 import get_historical_data import yfinance as yf import logging from collections import Counter @@ -21,6 +21,7 @@ import statistics import heapq import requests +from strategies.talib_indicators import * # MongoDB connection string @@ -98,7 +99,7 @@ def main(): market_collection.update_one({}, {"$set": {"market_status": status}}) - + if status == "open": logging.info("Market is open. Waiting for 60 seconds.") if not ndaq_tickers: @@ -119,6 +120,7 @@ def main(): decisions_and_quantities = [] try: trading_client = TradingClient(API_KEY, API_SECRET) + account = trading_client.get_account() buying_power = float(account.cash) @@ -127,20 +129,16 @@ def main(): mongo_client = MongoClient(mongo_url) trades_db = mongo_client.trades portfolio_collection = trades_db.portfolio_value - previous_portfolio_value = portfolio_collection.find_one({'portfolio_percentage': {'$exists': True}})['portfolio_percentage'] - previous_ndaq_percentage = portfolio_collection.find_one({'ndaq_percentage': {'$exists': True}})['ndaq_percentage'] - previous_spy_percentage = portfolio_collection.find_one({'spy_percentage': {'$exists': True}})['spy_percentage'] + """ we update instead of insert """ - portfolio_collection.update_one({}, {"$set": {"portfolio_percentage": (portfolio_value-50000)/50000}}) - portfolio_collection.update_one({}, {"$set": {"ndaq_percentage": (get_latest_price('QQQ')-503.17)/503.17}}) - portfolio_collection.update_one({}, {"$set": {"spy_percentage": (get_latest_price('SPY')-590.50)/590.50}}) + portfolio_collection.update_one({"name" : "portfolio_percentage"}, {"$set": {"portfolio_percentage": (portfolio_value-50000)/50000}}) + portfolio_collection.update_one({"name" : "ndaq_percentage"}, {"$set": {"portfolio_percentage": (get_latest_price('QQQ')-503.17)/503.17}}) + portfolio_collection.update_one({"name" : "spy_percentage"}, {"$set": {"portfolio_percentage": (get_latest_price('SPY')-590.50)/590.50}}) - historical_data = get_historical_data(ticker, data_client) - ticker_yahoo = yf.Ticker(ticker) - data = ticker_yahoo.history() + historical_data = get_data(ticker) current_price = None while current_price is None: try: @@ -151,13 +149,13 @@ def main(): asset_info = asset_collection.find_one({'symbol': ticker}) portfolio_qty = asset_info['quantity'] if asset_info else 0.0 - + print(f"Portfolio quantity for {ticker}: {portfolio_qty}") """ use weight from each strategy to determine how much each decision will be weighed. weights will be in decimal """ for strategy in strategies: - decision, quantity, _ = strategy(ticker, current_price, historical_data, + decision, quantity = simulate_strategy(strategy, ticker, current_price, historical_data, buying_power, portfolio_qty, portfolio_value) weight = strategy_to_coefficient[strategy.__name__] @@ -169,14 +167,18 @@ def main(): for now in bull: 15000 for bear: 5000 """ - print(f"Ticker{ticker} holding is currently at percentage of portfolio value: {(portfolio_qty * current_price) / portfolio_value}") + if decision == "buy" and float(account.cash) > 15000 and (((quantity + portfolio_qty) * current_price) / portfolio_value) < 0.1: heapq.heappush(buy_heap, (-(buy_weight-(sell_weight + hold_weight)), quantity, ticker)) elif decision == "sell" and portfolio_qty > 0: + print(f"Executing SELL order for {ticker}") + + order = place_order(trading_client, ticker, OrderSide.SELL, qty=quantity, mongo_url=mongo_url) # Place order using helper logging.info(f"Executed SELL order for {ticker}: {order}") + else: logging.info(f"Holding for {ticker}, no action taken.") @@ -189,8 +191,10 @@ def main(): try: buy_coeff, quantity, ticker = heapq.heappop(buy_heap) print(f"buy_coeff: {buy_coeff}, quantity: {quantity}, ticker: {ticker}") + order = place_order(trading_client, ticker, OrderSide.BUY, qty=quantity, mongo_url=mongo_url) # Place order using helper logging.info(f"Executed BUY order for {ticker}: {order}") + trading_client = TradingClient(API_KEY, API_SECRET) account = trading_client.get_account()