From 3d016a773796f40df0ba57f39e5e454afb595287 Mon Sep 17 00:00:00 2001 From: Jack Song <133342301@163.com> Date: Tue, 11 Jun 2019 11:33:40 +1000 Subject: [PATCH] Minor updates 3 --- README.md | 4 ++-- alpha/strategies/strategy_2.ipynb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index dd815b7..e393a38 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ This mini QuantTrading project will have the following features: ### TradeStrategy x 2 -#### Strategy 1: Trend Following. +#### Strategy 1: Trend Following When price rises above an absolute threshold `p_change_threshold` percent, default to 2%. @@ -37,7 +37,7 @@ Buy and hold for `hold_stock_threshold` days, default to 20. [Source File](./alpha/strategies/strategy_1.ipynb) & [Demo Usage](./alpha/strategies/strategy_1_usage.ipynb). -#### Strategy 2: Reversion. +#### Strategy 2: Mean Reversion When price falls consecutively for two days, and cumulatively more than `p_change_threshold` percent in total, default to 10%. diff --git a/alpha/strategies/strategy_2.ipynb b/alpha/strategies/strategy_2.ipynb index 56bbc31..0e138b5 100644 --- a/alpha/strategies/strategy_2.ipynb +++ b/alpha/strategies/strategy_2.ipynb @@ -4,7 +4,7 @@ "cell_type": "code", "execution_count": 22, "outputs": [], - "source": "# %%file strategy_2.py\n\nimport import_ipynb\nfrom strategy_base import TradeStrategyBase\n\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\n\nclass TradeStrategy2(TradeStrategyBase):\n \"\"\"\n Trade Strategy 2: Reversion Strategy. \n When price falls two days in a row, and cumulatively more than x percent (_p_change_threshold) in total, default to 10%.\n Buy and hold for a number of days (_hold_stock_threshold) days, default to 20. \n \"\"\"\n # Absolute threshold for buy in\n _p_change_threshold \u003d 10\n # Number of days to hold after Buy\n _hold_stock_threshold \u003d 10\n \n def __init__(self, p_change_threshold:float \u003d 10.0, hold_stock_threshold:int \u003d 10, should_log:bool \u003d False, should_plot:bool \u003d False, axs \u003d None):\n \"\"\"\n Initialize Strategy with given parameters\n :type p_change_threshold: float\n :type hold_stock_threshold: int \n :type should_log: bool\n :type should_plot: bool\n :param p_change_threshold: Absolute threshold for a stock to rise in two days. E.g. 7.5% \u003d 7.5 \n :param hold_stock_threshold: Number of days to hold a stock. E.g. 20 days \u003d 20\n :param should_log Whether or not log the strategy\n :param should_plot Whether or not plot the strategy\n \"\"\"\n self._p_change_threshold \u003d p_change_threshold\n self._hold_stock_threshold \u003d hold_stock_threshold\n self._should_log \u003d should_log\n self._should_plot \u003d should_plot\n self._axs \u003d axs\n \n self._held_tradedays \u003d pd.DataFrame()\n self._previous_tradeday \u003d None\n self._held_period_days \u003d 0\n \n def trade(self, date:pd.Timestamp, tradeday: pd.Series):\n \"\"\"\n Perform Analysis, Decide on Trade, and Execute Trade\n :type date: pd.Timestamp\n :type tradeday: pd.Series\n :param date: The pandas DataFrame date\n :param tradeday: The pandas DateFrame Series representing a trade day\n :return: \n \"\"\"\n \n \"\"\"\n Firstly, Increment holding date count\n \"\"\"\n if self._held_period_days !\u003d 0:\n # Increment date\n self._held_period_days +\u003d 1\n # Is currently holding, attach new tradeday in DataFrame\n self._held_tradedays \u003d self._held_tradedays.append(tradeday)\n \n \"\"\"\n Secondly, Buying\n \"\"\"\n if self._evaluate_buying(date\u003ddate,\n tradeday\u003dtradeday):\n self._execute_buying(date\u003ddate,\n tradeday\u003dtradeday)\n \n \"\"\"\n Lastly, Selling\n \"\"\"\n if self._evaluate_selling(date\u003ddate,\n tradeday\u003dtradeday):\n self._execute_selling(date\u003ddate,\n tradeday\u003dtradeday)\n \n def _evaluate_buying(self, date:pd.Timestamp, tradeday: pd.Series):\n \"\"\"\n Evaluate whether or not BUY should be executed\n :type date: pd.Timestamp\n :type tradeday: pd.Series\n :param date: The pandas DataFrame date\n :param tradeday: The pandas DateFrame Series representing a trade day\n \"\"\"\n trade_day: pd.Series \u003d tradeday.copy() # Create a copy() in case we need to change it.\n if self._held_period_days \u003d\u003d 0 and self._previous_tradeday is not None:\n # trade_day.change \u003c 0 : Tells if price dropped\n is_today_price_down \u003d trade_day.p_change \u003c 0\n # Check if yesterday was down\n is_yesterday_price_down \u003d self._previous_tradeday.p_change \u003c 0\n \n # Sum of all drops\n total_down_rate \u003d trade_day.p_change + self._previous_tradeday.p_change\n \n # Set previous_tradeday to today\n self._previous_tradeday \u003d tradeday\n \n if is_today_price_down and \\\n is_yesterday_price_down and \\\n np.abs(total_down_rate) \u003e self._p_change_threshold:\n return True\n else:\n return False\n else:\n # Set previous_tradeday to today\n self._previous_tradeday \u003d tradeday\n return False\n \n def _execute_buying(self, date:pd.Timestamp, tradeday: pd.Series):\n \"\"\"\n How BUY should be executed\n :type date: pd.Timestamp\n :type tradeday: pd.Series\n :param date: The pandas DataFrame date\n :param tradeday: The pandas DateFrame Series representing a trade day\n \"\"\"\n if self._should_log:\n print(\"Bought on {} at ${}.\".format(date, tradeday.close))\n self._held_period_days +\u003d 1 # Start holding date count\n self._held_tradedays \u003d pd.DataFrame(tradeday).T # Transpose of Series\n self._last_buy_date \u003d date\n\n def _evaluate_selling(self, date:pd.Timestamp, tradeday: pd.Series):\n \"\"\"\n Evaluate whether or not SELL should be executed\n :type date: pd.Timestamp\n :type tradeday: pd.Series\n :param date: The pandas DataFrame date\n :param tradeday: The pandas DateFrame Series representing a trade day\n \"\"\"\n if self._held_period_days \u003e\u003d self._hold_stock_threshold:\n # When holding period exceeds hold_stock_threshold, sell stocks\n return True\n else:\n return False\n \n def _execute_selling(self, date:pd.Timestamp, tradeday: pd.Series):\n \"\"\"\n How SELL should be executed\n :type date: pd.Timestamp\n :type tradeday: pd.Series\n :param date: The pandas DataFrame date\n :param tradeday: The pandas DateFrame Series representing a trade day\n \"\"\" \n if self._should_log:\n print(\"Sold on {} at ${}.\".format(date, tradeday.close))\n if self._should_plot:\n self._plot_trade(axs\u003dself._axs,\n buy_date\u003dself._last_buy_date, \n sell_date\u003ddate)\n self._previous_tradeday \u003d None # Reset last tradeday\n self._held_period_days \u003d 0 # Reset holding count \n self._last_buy_date \u003d None # Reset last buy date\n\n def _plot_trade(self, axs, buy_date, sell_date):\n\n print(\"Todo: Plotting {} {}\".format(buy_date, sell_date))\n\n # buy_tradeday \u003d self._held_tradedays[buy_date.date()]\n # sell_tradeday \u003d self._held_tradedays[sell_date.date()]\n # print(\"Bought at {}, Sold at {}\".format(buy_tradeday.close, sell_tradeday.close))\n\n # drawer \u003d plt if axs is None else axs\n # \n # # Mark red for up and green for down, slicing using start and end\n # if sell_tradeday.close \u003c buy_tradeday.close:\n # drawer.fill_between(self._held_tradedays.index[buy_date:sell_date], 0,\n # self._held_tradedays[\u0027close\u0027][buy_date:sell_date], color\u003d\u0027red\u0027,\n # alpha\u003d.38)\n # is_win \u003d False\n # else:\n # drawer.fill_between(amex_df.index[buy_date:sell_date], 0,\n # amex_df[\u0027close\u0027][buy_date:sell_date], color\u003d\u0027green\u0027,\n # alpha\u003d.38)\n # is_win \u003d True\n # \n # return is_win\n \n @property\n def trade_profit(self):\n if \u0027p_change\u0027 in self._held_tradedays.columns:\n profit_array \u003d self._held_tradedays.p_change/100 + 1\n profit_rate \u003d np.product(profit_array)-1\n return profit_rate\n else:\n return 0\n \n @property\n def p_change_threshold(self):\n return self._p_change_threshold\n \n @property\n def keep_stock_threshold(self):\n return self._hold_stock_threshold\n ", + "source": "# %%file strategy_2.py\n\nimport import_ipynb\nfrom strategy_base import TradeStrategyBase\n\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\n\nclass TradeStrategy2(TradeStrategyBase):\n \"\"\"\n Trade Strategy 2: Mean Reversion. \n When price falls two days in a row, and cumulatively more than x percent (_p_change_threshold) in total, default to 10%.\n Buy and hold for a number of days (_hold_stock_threshold) days, default to 20. \n \"\"\"\n # Absolute threshold for buy in\n _p_change_threshold \u003d 10\n # Number of days to hold after Buy\n _hold_stock_threshold \u003d 10\n \n def __init__(self, p_change_threshold:float \u003d 10.0, hold_stock_threshold:int \u003d 10, should_log:bool \u003d False, should_plot:bool \u003d False, axs \u003d None):\n \"\"\"\n Initialize Strategy with given parameters\n :type p_change_threshold: float\n :type hold_stock_threshold: int \n :type should_log: bool\n :type should_plot: bool\n :param p_change_threshold: Absolute threshold for a stock to rise in two days. E.g. 7.5% \u003d 7.5 \n :param hold_stock_threshold: Number of days to hold a stock. E.g. 20 days \u003d 20\n :param should_log Whether or not log the strategy\n :param should_plot Whether or not plot the strategy\n \"\"\"\n self._p_change_threshold \u003d p_change_threshold\n self._hold_stock_threshold \u003d hold_stock_threshold\n self._should_log \u003d should_log\n self._should_plot \u003d should_plot\n self._axs \u003d axs\n \n self._held_tradedays \u003d pd.DataFrame()\n self._previous_tradeday \u003d None\n self._held_period_days \u003d 0\n \n def trade(self, date:pd.Timestamp, tradeday: pd.Series):\n \"\"\"\n Perform Analysis, Decide on Trade, and Execute Trade\n :type date: pd.Timestamp\n :type tradeday: pd.Series\n :param date: The pandas DataFrame date\n :param tradeday: The pandas DateFrame Series representing a trade day\n :return: \n \"\"\"\n \n \"\"\"\n Firstly, Increment holding date count\n \"\"\"\n if self._held_period_days !\u003d 0:\n # Increment date\n self._held_period_days +\u003d 1\n # Is currently holding, attach new tradeday in DataFrame\n self._held_tradedays \u003d self._held_tradedays.append(tradeday)\n \n \"\"\"\n Secondly, Buying\n \"\"\"\n if self._evaluate_buying(date\u003ddate,\n tradeday\u003dtradeday):\n self._execute_buying(date\u003ddate,\n tradeday\u003dtradeday)\n \n \"\"\"\n Lastly, Selling\n \"\"\"\n if self._evaluate_selling(date\u003ddate,\n tradeday\u003dtradeday):\n self._execute_selling(date\u003ddate,\n tradeday\u003dtradeday)\n \n def _evaluate_buying(self, date:pd.Timestamp, tradeday: pd.Series):\n \"\"\"\n Evaluate whether or not BUY should be executed\n :type date: pd.Timestamp\n :type tradeday: pd.Series\n :param date: The pandas DataFrame date\n :param tradeday: The pandas DateFrame Series representing a trade day\n \"\"\"\n trade_day: pd.Series \u003d tradeday.copy() # Create a copy() in case we need to change it.\n if self._held_period_days \u003d\u003d 0 and self._previous_tradeday is not None:\n # trade_day.change \u003c 0 : Tells if price dropped\n is_today_price_down \u003d trade_day.p_change \u003c 0\n # Check if yesterday was down\n is_yesterday_price_down \u003d self._previous_tradeday.p_change \u003c 0\n \n # Sum of all drops\n total_down_rate \u003d trade_day.p_change + self._previous_tradeday.p_change\n \n # Set previous_tradeday to today\n self._previous_tradeday \u003d tradeday\n \n if is_today_price_down and \\\n is_yesterday_price_down and \\\n np.abs(total_down_rate) \u003e self._p_change_threshold:\n return True\n else:\n return False\n else:\n # Set previous_tradeday to today\n self._previous_tradeday \u003d tradeday\n return False\n \n def _execute_buying(self, date:pd.Timestamp, tradeday: pd.Series):\n \"\"\"\n How BUY should be executed\n :type date: pd.Timestamp\n :type tradeday: pd.Series\n :param date: The pandas DataFrame date\n :param tradeday: The pandas DateFrame Series representing a trade day\n \"\"\"\n if self._should_log:\n print(\"Bought on {} at ${}.\".format(date, tradeday.close))\n self._held_period_days +\u003d 1 # Start holding date count\n self._held_tradedays \u003d pd.DataFrame(tradeday).T # Transpose of Series\n self._last_buy_date \u003d date\n\n def _evaluate_selling(self, date:pd.Timestamp, tradeday: pd.Series):\n \"\"\"\n Evaluate whether or not SELL should be executed\n :type date: pd.Timestamp\n :type tradeday: pd.Series\n :param date: The pandas DataFrame date\n :param tradeday: The pandas DateFrame Series representing a trade day\n \"\"\"\n if self._held_period_days \u003e\u003d self._hold_stock_threshold:\n # When holding period exceeds hold_stock_threshold, sell stocks\n return True\n else:\n return False\n \n def _execute_selling(self, date:pd.Timestamp, tradeday: pd.Series):\n \"\"\"\n How SELL should be executed\n :type date: pd.Timestamp\n :type tradeday: pd.Series\n :param date: The pandas DataFrame date\n :param tradeday: The pandas DateFrame Series representing a trade day\n \"\"\" \n if self._should_log:\n print(\"Sold on {} at ${}.\".format(date, tradeday.close))\n if self._should_plot:\n self._plot_trade(axs\u003dself._axs,\n buy_date\u003dself._last_buy_date, \n sell_date\u003ddate)\n self._previous_tradeday \u003d None # Reset last tradeday\n self._held_period_days \u003d 0 # Reset holding count \n self._last_buy_date \u003d None # Reset last buy date\n\n def _plot_trade(self, axs, buy_date, sell_date):\n\n print(\"Todo: Plotting {} {}\".format(buy_date, sell_date))\n\n # buy_tradeday \u003d self._held_tradedays[buy_date.date()]\n # sell_tradeday \u003d self._held_tradedays[sell_date.date()]\n # print(\"Bought at {}, Sold at {}\".format(buy_tradeday.close, sell_tradeday.close))\n\n # drawer \u003d plt if axs is None else axs\n # \n # # Mark red for up and green for down, slicing using start and end\n # if sell_tradeday.close \u003c buy_tradeday.close:\n # drawer.fill_between(self._held_tradedays.index[buy_date:sell_date], 0,\n # self._held_tradedays[\u0027close\u0027][buy_date:sell_date], color\u003d\u0027red\u0027,\n # alpha\u003d.38)\n # is_win \u003d False\n # else:\n # drawer.fill_between(amex_df.index[buy_date:sell_date], 0,\n # amex_df[\u0027close\u0027][buy_date:sell_date], color\u003d\u0027green\u0027,\n # alpha\u003d.38)\n # is_win \u003d True\n # \n # return is_win\n \n @property\n def trade_profit(self):\n if \u0027p_change\u0027 in self._held_tradedays.columns:\n profit_array \u003d self._held_tradedays.p_change/100 + 1\n profit_rate \u003d np.product(profit_array)-1\n return profit_rate\n else:\n return 0\n \n @property\n def p_change_threshold(self):\n return self._p_change_threshold\n \n @property\n def keep_stock_threshold(self):\n return self._hold_stock_threshold\n ", "metadata": { "pycharm": { "metadata": false,