DSL Script Structure and Best Practices
This documentation outlines the structure and best practices for using our Domain Specific Language (DSL) to develop trading strategies. As of now, it is beta and still being constantly improved. There is a considerable amount of tech debt.
Script Structure
Initialization (Critical Section)
User-Defined Strategy Logic
Result Handling (Critical Section)
Each section serves a distinct purpose and is essential for the proper functioning of your strategy.
1. Initialization (Critical Section)
Purpose: The initialization section is responsible for setting up the environment required for your trading strategy. This includes initializing data providers, importing necessary modules, and configuring global settings.
Example:
Key Points:
Do Not Modify: This section is critical for the application. Any changes may result in incorrect initialization of the trading environment.
Global Variables: The
globals()
function retrieves global variables such asticker_input
,start_date
, andend_date
. These are essential for configuring the strategy.Context: The
context
dictionary stores all initialized components, such as data providers, modules, and UI elements, which are accessible throughout the script.
2. User-Defined Strategy Logic
Purpose: This section is where you define and customize your trading strategy. It allows you to apply technical indicators, execute trading commands, and implement your logic for making trade decisions.
Example:
Key Points:
Flexibility: This section is designed for maximum flexibility, allowing you to implement any trading logic you desire.
Error Handling: Use
try-except
blocks to catch and log any errors that occur during strategy execution.Accessing Context: All necessary modules and data providers are available in the
context
dictionary. Use this to access pre-initialized components.
3. Result Handling (Critical Section)
Purpose: This section handles the output of your strategy, including saving trade history, calculating performance metrics, and plotting results. It is critical for generating and managing the results of your strategy.
Example:
Key Points:
Do Not Modify: Similar to the initialization section, this part is critical. Modifications should only be made if you fully understand the impact on result generation.
Result Management: The
StrategyResultHandler
manages the process of saving results to a file and plotting performance metrics. Customize this class if you need to alter how results are handled.
Best Practices
Keep Critical Sections Intact: The critical sections are essential for the correct operation of your strategy. Avoid making changes to these unless necessary.
Leverage the
context
Dictionary: All initialized components are stored incontext
. This allows for consistent access throughout your strategy script.Modular Design: Import additional commands, indicators, or utilities as needed. This keeps your code clean and maintainable.
Error Logging: Ensure all errors are logged for easier debugging and strategy optimization.
Importing Additional Functions or Modules
If your strategy requires additional functionality, such as custom commands or indicators, you can import them as follows:
Conclusion
This structured approach ensures that your trading strategies are both powerful and maintainable. By following these guidelines, you can effectively leverage the DSL to develop and test a wide range of trading strategies.
Note on Using Modules in DSL Scripts
In your DSL scripts, there are two primary approaches to importing and utilizing modules: Standard Python Imports and Dynamic Imports via ImportCommand
. Each method serves different purposes and offers distinct advantages depending on your use case. Below, we outline both methods to help you decide which is most appropriate for your needs.
1. Standard Python Import:
If you know in advance which modules your strategy requires, the conventional Python import statement is the most straightforward and efficient method.
Example:
How to Use: Once imported, these modules are immediately available for use throughout your script.
Advantages: This method is clear, explicit, and easy to maintain. It ensures that all dependencies are loaded at the start of the script, making debugging simpler.
2. Dynamic Import Using ImportCommand
:
Dynamic importing allows you to import modules at runtime, providing flexibility for scripts that need to adapt to different conditions or configurations.
Step 1: Defining Modules for Dynamic Import
Within the StrategyInitializer
class, the ImportCommand
is used to specify the modules that may be needed dynamically:
Explanation: This list covers a wide range of essential modules that are dynamically imported when your strategy is initialized. These modules are then accessible through the
context
dictionary.
Step 2: Executing Dynamic Import During Script Execution
If additional modules are required at runtime, they can be imported dynamically using the ImportCommand
(here is how 'numpy' and 'scipy' would be imported using dynamic imports):
Explanation:
Here,
ImportCommand
is accessed via thecontext
dictionary.Modules such as
'numpy'
and'scipy'
are dynamically imported as needed during script execution.The
execute()
method returns a dictionary (imported_modules
) containing the imported modules, making them available for immediate use.
Step 3: Utilizing Dynamically Imported Modules
Once imported, these modules can be used in your strategy as follows:
Explanation: You can now access and use these dynamically imported modules just like any other standard imports.
Summary of Import Methods:
Standard Import: Ideal for scenarios where all required modules are known at the outset. This method promotes clarity and explicitness in your code, making it easier to read and maintain.
Dynamic Import: Best suited for strategies requiring flexibility, such as those that adapt based on runtime conditions or need to minimize memory usage by loading modules only when necessary.
Last updated