.. _user.project1: ===================================== Your First Automated Trading Strategy ===================================== In this tutorial you will be led through the creation of an automated trading strategy. Topics Covered ~~~~~~~~~~~~~~ - Subscribing to real time signals from a study in SC - Submitting a simple market order - Handling reversals - Using the SC trade window - Submitting attached orders - Modifying orders - Reading position information - Limiting trading to specific hours in the day - Flattening a position - Retrieving data from 2 charts (2 timeframes) Setup ~~~~~ Open a 5 minute ESU24-CME chart. Add the SC-dX custom study and give the key ``signal``. To get started we need some sort of signal to tell us when to make trades. Add the ``Stochastic Crossover System`` study to the chart and verify that you can now see buy and sell signals drawn on the chart as green and red arrows. The Basic Strategy ~~~~~~~~~~~~~~~~~~ Using the signals from the stochastic crossover system, we want the following strategy: For bearish signals: - If we are long: reverse the position - If we are short: do nothing - If we are flat: enter short For bullish signals: - If we are long: do nothing - If we are short: reverse the position - If we are flat: enter long Thus, once we are in the the market, with this strategy we will never exit. Getting the Signal ------------------ In a new python file, test that we can connect to Sierra Chart: .. literalinclude:: examples/project1/version0.py :caption: autotrader_ver0.py :linenos: :lineno-match: :end-before: S0 Now we want to access the signals in python. Looking at the ``Stochastic Crossover System`` study settings reveals that these signals are subgraphs with ID 1 for the buy and ID 2 for the sell subgraph. .. image:: media/project1/figure0.png We can subscribe to data about these subgraphs with the :func:`~trade29.sc.SCBridge.subscribe_to_chart_data` method. .. literalinclude:: examples/project1/version0.py :caption: autotrader_ver0.py :linenos: :lineno-match: :start-after: S0 :end-before: S1 Lets throw in some boilerplate code to print the fetched data as a dataframe to get a sense for what it looks like. .. literalinclude:: examples/project1/version0.py :caption: autotrader_ver0.py :linenos: :lineno-match: :start-after: S1 To test this we can use Sierra Chart's replay feature. Open the replay control panel in the top bar through ``Chart>Replay Chart>Replay Chart (Control Panel)``, set the speed to something fast like 60, and scroll back through the chart (near where a signal will be given). Run the python file we just wrote, and hit ``Play`` in the Sierra Chart replay panel. We expect to see a bunch of single row DataFrames. Here is a sample output: .. code-block:: python IsBarClosed ID2.SG1 ID2.SG2 DateTime 2024-06-21 06:45:00 True 0.0 0.0 IsBarClosed ID2.SG1 ID2.SG2 DateTime 2024-06-21 06:50:00 True 0.0 0.0 IsBarClosed ID2.SG1 ID2.SG2 DateTime 2024-06-21 06:55:00 True 0.0 0.0 IsBarClosed ID2.SG1 ID2.SG2 DateTime 2024-06-21 07:00:00 True 5542.87 0.0 IsBarClosed ID2.SG1 ID2.SG2 DateTime 2024-06-21 07:05:00 True 0.0 0.0 IsBarClosed ID2.SG1 ID2.SG2 DateTime 2024-06-21 07:10:00 True 5541.69 0.0 Observe how when there is no arrow drawn on the subgraph, the value is 0, and when there is, the value is the price at which it is drawn. Thus by checking if the value in this DataFrame is not 0, we can know whether we have a signal or not. So our logic would look something like this: .. literalinclude:: examples/project1/version1-0.py :caption: autotrader_ver1.py :linenos: :lineno-match: :start-after: S1 Trading on the Signal --------------------- Let's start filling this in. Firstly, we need to get the actual values from the response DataFrame. Recall that SG1 was the buy signal and SG2 was the sell. .. literalinclude:: examples/project1/version1-1.py :caption: autotrader_ver1.py :linenos: :lineno-match: :start-after: S1 Now that we have the signals as their own variables, we can fill in the logic for what to do on a signal. Recall the outline of the strategy: For bearish signals: - If we are long: reverse the position - If we are short: do nothing - If we are flat: enter short For bullish signals: - If we are long: do nothing - If we are short: reverse the position - If we are flat: enter long Given this, let ``position`` be our current position; the logic would look something like this: .. literalinclude:: examples/project1/version1-2.py :caption: autotrader_ver1.py :linenos: :lineno-match: :start-after: S1 To get this position, we will add a new bridge subscription, and initialize a position variable: .. literalinclude:: examples/project1/version1-3.py :caption: autotrader_ver1.py :linenos: :lineno-match: :start-after: S0 :end-before: S1 :emphasize-lines: 10, 12 Now that we have two subscriptions, we need to filter the bridge response queue based on them: .. literalinclude:: examples/project1/version1-3.py :caption: autotrader_ver1.py :linenos: :lineno-match: :start-after: S1 :emphasize-lines: 6, 7 Finally, its time to fill in all of the TODOs with :func:`~trade29.sc.SCBridge.submit_order` calls. For this tutorial we are going to enter with a quantity of 5. .. admonition:: Why do we combine the cases for flat and long/short? The :func:`~trade29.sc.SCBridge.submit_order` call for entering and reversing into a position is actually the same. In the SC-dX study settings ``SupportReversals`` is ``Yes`` by default. As per the `Sierra Chart docs `_, when this option is enabled, an order that goes against the current position will first flatten the position, then execute the order. Thus to enter long and reverse into long from a short position is the same action of just buying whatever quantity you want to end up with. .. literalinclude:: examples/project1/version1-4.py :caption: autotrader_ver1.py :linenos: :lineno-match: :start-after: S1 :emphasize-lines: 16-19, 22-25 Awesome! You have just finished coding your very first automated trading strategy in SC-Py. Attach the trade window to the chart under the ``Trade`` menu in the top bar, run the Python script, and replay your chart to test that the strategy works fine. Adding Exits in Sierra Chart ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Now we are going to add a stop and a target in that SC trade window you just opened. In the trade window, go to the Targets tab, and hit add to add a new target. Configure it as a limit order with an offset of 60: .. image:: media/project1/figure1.png .. admonition:: Why don't we set a quantity for attached orders? Sierra Chart will automatically increase the quantity of the order group we defined to match the quantity of the main order we submit. Additionally, if we do set a OCO quantity in the SC Trade Window, it is expected to match the quantity under the Main tab, and will be changed if it doesn't. Now hit add again, and configure this order as a stop with an offset of 60. Make sure they both belong to OCO group 1. .. image:: media/project1/figure2.png If you tried running your python script now, you might notice that it doesn't use these attached orders, you need to do 2 things. First in the SC Trade Window check ``Use Attached Orders`` in the Main tab, then set the ``attach_orders_sc_trade_window`` parameter in the :meth:`~trade29.sc.SCBridge.submit_order` method: .. literalinclude:: examples/project1/version2-0.py :caption: autotrader_ver2.py :linenos: :lineno-match: :start-after: S2 :emphasize-lines: 5, 9 Now when you run you can see that a limit order and stop order are created on entrance. Awesome! Confirming With A Trend ~~~~~~~~~~~~~~~~~~~~~~~ We've come really far from our empty python file. We are now recieving a signal from a Sierra Chart study, and trading on it with stops and limits in place. This is a very strong skeleton for a trading strategy, but we can make it safer. Using some trend indicator, we want to only enter when the direction of the signal aligns with the direction of the trend indicator. For example, suppose we get a bearish signal. If the trend is bearish too, then we can enter short, however if the trend is bullish, its safer to go flat. Thus our logic would look something like this: .. literalinclude:: examples/project1/version3-0.py :caption: autotrader_ver3.py :linenos: :lineno-match: :start-after: S1 For the trend indicator we are going to take the slope of an exponential moving average. In Sierra Chart, add the ``Moving Average - Exponential`` study to the chart. Note the study ID (which should be 3) and the ID of its only subgraph (SG1). Now lets add this subgraph to our chart data subscription, and lets store the trend value from one bar ago: .. literalinclude:: examples/project1/version3-1.py :caption: autotrader_ver3.py :linenos: :lineno-match: :start-after: S0 :end-before: S1 :emphasize-lines: 3, 8, 15-20 Now lets implement some logic for figuring out if our trend is bearish or bullish. .. literalinclude:: examples/project1/version3-1.py :caption: autotrader_ver3.py :linenos: :lineno-match: :start-after: S1 :end-before: S2 A Dynamic Stop and Target ------------------------- Currently we are setting the stop and target in the Sierra Chart trade window. This was fine up until now, but our next step is going to be to set the stop and target more intelligently. Instead of having a hard set stop and target offset, we are going to dynamically set our stop and target offsets based on Sierra Chart's ``Average True Range`` study. Attaching Orders in Python ~~~~~~~~~~~~~~~~~~~~~~~~~~ Firstly, lets move the setting of the stops and targets to our python code. The :meth:`~trade29.sc.SCBridge.submit_order` method has a parameter for OCOs, AKA attached orders. This parameter is a list of :class:`~trade29.sc.AttachedOrder` . We need to add this as an import. .. literalinclude:: examples/project1/version4-0.py :caption: autotrader_ver4.py :linenos: :lineno-match: :emphasize-lines: 1 :end-before: S0 Now we need to create an attached order, and supply it to the :meth:`~trade29.sc.SCBridge.submit_order` method. .. literalinclude:: examples/project1/version4-0.py :caption: autotrader_ver4.py :linenos: :lineno-match: :emphasize-lines: 1, 8, 15 :start-after: S2 Setting Offsets Dynamically ~~~~~~~~~~~~~~~~~~~~~~~~~~~ We expect that if we run this it will have the exact same behaviour as before, as we set the exact same stops and targets in python as we had previously in Sierra Chart. Now instead of setting these stops to a constant value, lets make them dynamic. In Sierra Chart, add the ``Average True Range`` study. Note its ID and how it only has one subgraph (the one we want) with the ID 1. Let's add this as a subscription like we did before with our trend. .. literalinclude:: examples/project1/version4-1.py :caption: autotrader_ver4.py :linenos: :lineno-match: :emphasize-lines: 5, 10 :start-after: S0 :end-before: S1 And now we can set our target and stop offsets to this ATR value! .. literalinclude:: examples/project1/version4-1.py :caption: autotrader_ver4.py :linenos: :lineno-match: :emphasize-lines: 3, 5 :start-after: S2