<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jungle Sven</title>
    <description>The latest articles on DEV Community by Jungle Sven (@jungle_sven).</description>
    <link>https://dev.to/jungle_sven</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F940906%2F89b10f9d-cdea-4198-9b9b-edad1b7853d7.jpg</url>
      <title>DEV Community: Jungle Sven</title>
      <link>https://dev.to/jungle_sven</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jungle_sven"/>
    <language>en</language>
    <item>
      <title>Trading System Components</title>
      <dc:creator>Jungle Sven</dc:creator>
      <pubDate>Sat, 27 Jul 2024 05:07:57 +0000</pubDate>
      <link>https://dev.to/jungle_sven/trading-system-components-5f0b</link>
      <guid>https://dev.to/jungle_sven/trading-system-components-5f0b</guid>
      <description>&lt;p&gt;In the last article, I discussed best practices for developing trading software, such as using events, data storage, or separate configurations. This time, let's delve into the strategic part, specifically how to organize it effectively from an architectural standpoint.&lt;/p&gt;

&lt;h2&gt;
  
  
  Strategy Module
&lt;/h2&gt;

&lt;p&gt;The simplest approach is to assume that this part of the system receives input data, such as price changes, and generates events—signals. All logic can be encapsulated within this module. Here’s an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;signal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;calc_rsi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;signal&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;FLAT&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_event&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, we calculate the RSI and generate events like BUY or SELL based on it. This is a basic illustration, but the concept is clear. The signal might include the desired buy/sell price. Of course, a real trading algorithm is more complex, but you already know that!&lt;/p&gt;

&lt;h2&gt;
  
  
  Portfolio Module
&lt;/h2&gt;

&lt;p&gt;It's beneficial to have all data on balances or open positions gathered in one place. This way, you know your total holdings in USD or BTC. This knowledge is essential for determining the size of your orders when the system generates signals.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Calculate USD values
&lt;/span&gt;    &lt;span class="c1"&gt;# Calculate targets
&lt;/span&gt;    &lt;span class="c1"&gt;# Check targets
&lt;/span&gt;    &lt;span class="c1"&gt;# Generate orders
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This pseudocode outlines the following steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Calculate the total balances in USD&lt;/li&gt;
&lt;li&gt;Determine portfolio targets according to the strategy&lt;/li&gt;
&lt;li&gt;Check if current balances meet the targets&lt;/li&gt;
&lt;li&gt;Generate orders of the necessary size if there are discrepancies&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You get all the balance data, signals, verify if the positions align with the desired ones, and generate orders if they don't.&lt;/p&gt;

&lt;h2&gt;
  
  
  Risk Management Module
&lt;/h2&gt;

&lt;p&gt;This module is closely related to the Portfolio module. Sometimes, risk management logic can be implemented directly within it, especially if you're managing a small sum and have just started. For large firms, this could be the most complex system element, and each firm defines its precise algorithm. Here are some tasks that can be addressed within risk management:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Check correlations between positions to avoid 100% long or short&lt;/li&gt;
&lt;li&gt;Verify the maximum size of one position&lt;/li&gt;
&lt;li&gt;Halt the entire system if losses reach a certain percentage&lt;/li&gt;
&lt;li&gt;Stop the system in case of data stream failures or other components issues&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The longer you’re in the market, the more critical this part of the trading algorithm becomes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Execution Module
&lt;/h2&gt;

&lt;p&gt;After obtaining all price and balance data, generating signals, calculating the optimal portfolio size, and accounting for all possible risks, there’s no reason not to send an order to the exchange. This might seem like the simplest part unless you're implementing order routing across multiple exchanges. Usually, you format the order correctly and send it to the exchange you trade on.&lt;/p&gt;

&lt;p&gt;We discussed the functions of four modules, each of which is useful in 90% of trading algorithms. Structure your code, choose a good architecture, and maintaining and updating your trading system will be much less painful.&lt;/p&gt;

&lt;p&gt;The complete code will be available as an open-source trading algorithm for &lt;a href="http://aspis.finance" rel="noopener noreferrer"&gt;aspis.finance&lt;/a&gt;. It will include a couple of simple trading strategies, but the key feature is the ability to create storage through Aspis smart contracts, attract investor funds, and ensure transparent profit-sharing. You can develop your strategy, connect it to Aspis, your algorithm will trade on DEXs, and investors and managers (you) will earn profit through a smart contract. Stay tuned!&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>architecture</category>
      <category>python</category>
      <category>development</category>
    </item>
    <item>
      <title>Simple Yet Effective Architecture Patterns for Algorithmic Trading</title>
      <dc:creator>Jungle Sven</dc:creator>
      <pubDate>Wed, 17 Jul 2024 15:59:42 +0000</pubDate>
      <link>https://dev.to/jungle_sven/simple-yet-effective-architecture-patterns-for-algorithmic-trading-5745</link>
      <guid>https://dev.to/jungle_sven/simple-yet-effective-architecture-patterns-for-algorithmic-trading-5745</guid>
      <description>&lt;p&gt;In this thread, I'll show you how to develop trading software that is easy to maintain and update, while making it simple to collect statistics and track bugs.&lt;/p&gt;

&lt;p&gt;1/ &lt;strong&gt;Events-Driven Architecture&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;At the core of this architecture are EVENTS. Every significant action, such as receiving data or processing results, will generate events. This approach allows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clear tracking of system activities&lt;/li&gt;
&lt;li&gt;Standardized interaction between system components&lt;/li&gt;
&lt;li&gt;Easy addition of new event handlers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example of an event:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BalanceUpdate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Event&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;BALANCEUPDATE&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;timestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;timestamp&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;symbol&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;symbol&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In our trading system, we need balance updates via websocket or REST API. Other updates include price changes, order info, and internal system events. Each module handles a specific function and generates events like &lt;code&gt;BalanceUpdate&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;2/ &lt;strong&gt;Data Storage&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It's most efficient to store all data in a single repository. This includes price updates, balances, order data, signals, etc. Here's the workflow: The data module requests from a remote server, processes the response, and generates an event. Event handlers then save these data to the repository or trigger other handlers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Balances&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;usd_values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Storing data in memory is the simplest and fastest method, suitable for most trading algorithms that don't require permanent data storage. For more complex needs, use Redis for an in-memory storage interface, especially when accessing data from other microservices.&lt;/p&gt;

&lt;p&gt;3/ &lt;strong&gt;Configuration&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Separating settings into a config file is good practice for trading software and any other system. This centralizes settings, making changes easy to manage.&lt;/p&gt;

&lt;p&gt;Example config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[general]&lt;/span&gt;
&lt;span class="py"&gt;username&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;my_user_name&lt;/span&gt;

&lt;span class="nn"&gt;[trade]&lt;/span&gt;
&lt;span class="py"&gt;markets&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;['BTC/USDT', 'ETH/USDT']&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Read config with configparser:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;read_config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;config_object&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ConfigParser&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;config_object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;config.ini&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;settings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;sect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config_object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sect&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;sect&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;config_object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sections&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;
    &lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;trade&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;markets&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;eval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;trade&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;markets&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="c1"&gt;#string to dict
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;4/ &lt;strong&gt;Event Processing Loop&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Consider this the main file coordinating all system elements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Read settings from config&lt;/li&gt;
&lt;li&gt;Initialize system modules with settings&lt;/li&gt;
&lt;li&gt;Start the event processing loop&lt;/li&gt;
&lt;li&gt;Launch tasks like balance updates every minute or continuous websocket listening&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example balance update event handling:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;BALANCEUPDATE&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;BALANCE UPDATE&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data_storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;balances&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data_storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;calc_usd_value&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In summary, we've covered several components of a trading system without delving into specific strategies: events, data storage, config, and event loop. These practices are essential for developing any trading algorithm. In the next article, I'll discuss strategy modules, portfolio management, risk management, and order execution.&lt;/p&gt;

&lt;p&gt;All the code will be open-source and available upon the beta release of the service, developed in collaboration with &lt;a href="//aspis.finance"&gt;aspis.finance&lt;/a&gt; —a DeFi platform that makes trader-investor relationships transparent through smart contracts.&lt;/p&gt;

&lt;p&gt;Got questions? Reach out on TG @JungleSven.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Using Standard Deviation for Signals and Spreads</title>
      <dc:creator>Jungle Sven</dc:creator>
      <pubDate>Thu, 14 Sep 2023 13:11:53 +0000</pubDate>
      <link>https://dev.to/jungle_sven/using-standard-deviation-for-signals-and-spreads-13g8</link>
      <guid>https://dev.to/jungle_sven/using-standard-deviation-for-signals-and-spreads-13g8</guid>
      <description>&lt;p&gt;I'll show you how to use standard deviation to attempt to predict price reversals. As a bonus, we'll measure volatility ranges to place orders at optimal distances from the mean price.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--foOscNWj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/byhgq5klmy6ozkc8to1n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--foOscNWj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/byhgq5klmy6ozkc8to1n.png" alt="Image description" width="790" height="590"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Signals
&lt;/h3&gt;

&lt;p&gt;We'll try to predict price reversals from peak values to the mean using standard deviation. The idea is that the market often returns to mean values after "overheating." These peak values correspond to peak standard deviation values.&lt;/p&gt;

&lt;p&gt;Of course, this alone isn't enough to reliably predict price direction. So, we'll use two filters.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;First, the standard deviation must decrease to avoid shorting during continued growth and buying during declines.&lt;/li&gt;
&lt;li&gt;Second, the current price must be below the mean for buying and above it for selling.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Volatility Levels
&lt;/h3&gt;

&lt;p&gt;We need to know the current market volatility to adjust our targets, stops, and more.&lt;/p&gt;

&lt;p&gt;Typically, volatile periods form clusters. New information enters the market, traders use it, there's a price discovery process, and then the market calms down again.&lt;/p&gt;

&lt;p&gt;We'll take data from several days and calculate boundaries for five standard deviation levels. Then, we'll plot a chart to see the results.&lt;/p&gt;

&lt;p&gt;This is similar to the work I recently shared. However, in that case, I worked with tick data, and this time, I used candlesticks. &lt;a href="https://twitter.com/jungle_sven/status/1698726076212490307"&gt;Link to previous work&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can access the complete code &lt;a href="https://github.com/Jungle-Sven/std_dev_ohlcv/blob/main/std_dev_ohlcv.ipynb"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="//twitter.com/jungle_sven"&gt;twitter&lt;/a&gt;&lt;/p&gt;

</description>
      <category>algotrading</category>
      <category>statarb</category>
      <category>timeseries</category>
      <category>python</category>
    </item>
    <item>
      <title>Classification of Market Regimes Using Standard Deviation</title>
      <dc:creator>Jungle Sven</dc:creator>
      <pubDate>Mon, 04 Sep 2023 11:59:09 +0000</pubDate>
      <link>https://dev.to/jungle_sven/classification-of-market-regimes-using-standard-deviation-3g93</link>
      <guid>https://dev.to/jungle_sven/classification-of-market-regimes-using-standard-deviation-3g93</guid>
      <description>&lt;p&gt;Understanding what's currently happening in the market is crucial to make informed decisions. The concept of market regimes helps us gain insight into this. In broad terms, the market can be bullish, bearish, or range-bound. Professionals identify over ten different regimes.&lt;/p&gt;

&lt;p&gt;In this article, we'll explore how you can determine market regimes using standard deviation of prices. It allows us to assess how values in a dataset are distributed around the mean.&lt;/p&gt;

&lt;p&gt;In our dataset, we have 260,000 rows of data representing tick-by-tick price changes of ETH/USD over approximately 3 days collected via websockets.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;df = pd.read_csv(filename, names=['receive_timestamp', 'price'])&lt;br&gt;
df['receive_timestamp'] = pd.to_datetime(df['receive_timestamp'])&lt;br&gt;
df.set_index('receive_timestamp', inplace=True)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;First, we need to convert price changes into a logarithmic form, meaning we'll analyze percentage changes instead of regular prices. This helps smooth out volatility and enables easy comparisons across different periods.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;df['price'] = df['price'].apply(np.log)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now, let's calculate the standard deviation of logarithmic prices.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;df['std_dev'] = df['price'].rolling(window=100).std()&lt;br&gt;
df['std_dev_ma'] = df['std_dev'].rolling(3000).mean()&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Next, we'll define several levels and calculate the boundaries for these levels. Level 0 will correspond to the lowest volatility, with each subsequent group representing higher volatility.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;std_dev_ma_threshold_1 = df['std_dev_ma'].quantile(0.2)&lt;br&gt;
std_dev_ma_threshold_2 = df['std_dev_ma'].quantile(0.4)&lt;br&gt;
std_dev_ma_threshold_3 = df['std_dev_ma'].quantile(0.6)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now, we can create a price chart and mark our levels.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DrrA4sIZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q1j9txge5br23s0jnuvx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DrrA4sIZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q1j9txge5br23s0jnuvx.png" alt="Image description" width="800" height="410"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Gray and green zones represent low volatility, while red and black indicate the most volatile segments.&lt;/p&gt;

&lt;p&gt;Let's take a closer look at the high-volatility segment.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2sfHl0fr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/80djoa96tp9pyadsos6u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2sfHl0fr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/80djoa96tp9pyadsos6u.png" alt="Image description" width="800" height="410"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The faster the price changes, the higher the volatility and standard deviation.&lt;/p&gt;

&lt;p&gt;Now, let's examine a chart with a higher resolution.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--D2sypBgS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1iwaoa8obm0ozwsd7am0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--D2sypBgS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1iwaoa8obm0ozwsd7am0.png" alt="Image description" width="800" height="410"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These findings can be interpreted in various ways. You can enable or disable your trading strategies based on the market's volatility level. I plan to use this data to determine the distance from the mean price at which I'll place my orders as a market maker.&lt;/p&gt;

&lt;p&gt;Repository - &lt;a href="https://github.com/Jungle-Sven/std_dev_levels"&gt;Link&lt;/a&gt;&lt;br&gt;
Twitter - &lt;a href="https://twitter.com/jungle_sven"&gt;Link&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Calculate price stationarity for dYdX exchange.</title>
      <dc:creator>Jungle Sven</dc:creator>
      <pubDate>Tue, 22 Aug 2023 06:57:14 +0000</pubDate>
      <link>https://dev.to/jungle_sven/calculate-price-stationarity-for-dydx-exchange-bi0</link>
      <guid>https://dev.to/jungle_sven/calculate-price-stationarity-for-dydx-exchange-bi0</guid>
      <description>&lt;p&gt;Stationarity helps us to understand what strategies suit a market statistically. Stationarity shows how often prices revert to mean value.&lt;/p&gt;

&lt;p&gt;If stationarity is high, we can trade mean-revert strategies. If it is low - trending systems work better.&lt;/p&gt;

&lt;p&gt;I will show how to calculate stationarity for all markets in the dYdX exchange. &lt;/p&gt;

&lt;p&gt;To make calculations, we need a casual OHLCV. Large timeframes are better for seeing the big picture, as the situation in tiny timeframes changes too fast. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;TIMEFRAMES = ['1DAY', '4HOURS', '1HOUR', '15MINS']&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After we receive OHLCV, we can calculate stationarity in one line of code with statsmodels!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;result = adfuller(df.close)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It is easy to understand the result. If the p-value is less than 0.05, our prices are stationary.&lt;/p&gt;

&lt;p&gt;print('p-value: %.2f' % result[1])&lt;/p&gt;

&lt;p&gt;Some examples. Stationary prices:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--j1VsCdzw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7toe35f204av95m8ak18.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--j1VsCdzw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7toe35f204av95m8ak18.png" alt="" width="800" height="410"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hf0fB-fu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/adn2mpusnkvc6a4c13sv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hf0fB-fu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/adn2mpusnkvc6a4c13sv.png" alt="" width="800" height="410"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PbuhJ5m---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jgn8ie8lqbxksjxz7jxx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PbuhJ5m---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jgn8ie8lqbxksjxz7jxx.png" alt="" width="800" height="410"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Non-stationary prices:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--r3CCXlbS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9f23v9zcqii5hdt1jcom.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--r3CCXlbS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9f23v9zcqii5hdt1jcom.png" alt="" width="800" height="410"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aTyD2Bdw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a2mkai722zn9hukqs0hj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aTyD2Bdw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a2mkai722zn9hukqs0hj.png" alt="" width="800" height="410"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hYoLRvhj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hmaa3arjzgpkeh5wrmx3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hYoLRvhj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hmaa3arjzgpkeh5wrmx3.png" alt="" width="800" height="410"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can also take p-values from several timeframes and add and then select the largest and the smallest values to find out what markets tend to be more trending.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wbwNByjj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e6jlrw28m0dvza1l5nml.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wbwNByjj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e6jlrw28m0dvza1l5nml.png" alt="Image description" width="268" height="276"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The most trending markets: $MATIC, $AVAX, $CRV&lt;br&gt;
The least trending markets: $UMA, $CELO, $ETC&lt;/p&gt;

&lt;p&gt;The difference between the two groups is between 2 and 3. It can't guarantee a positive result, but it can help to select more optimal markets for a particular strategy or to filter a signal with this data. &lt;/p&gt;

&lt;p&gt;GitHub repo - &lt;a href="https://github.com/Jungle-Sven/stationarity"&gt;https://github.com/Jungle-Sven/stationarity&lt;/a&gt;&lt;br&gt;
Twitter - &lt;a href="https://twitter.com/jungle_sven"&gt;https://twitter.com/jungle_sven&lt;/a&gt;&lt;/p&gt;

</description>
      <category>algotrading</category>
      <category>statarb</category>
      <category>timeseries</category>
      <category>stationarity</category>
    </item>
    <item>
      <title>5 ways to store market data: CSV, SQLite, Postgres, Mongo, Arctic</title>
      <dc:creator>Jungle Sven</dc:creator>
      <pubDate>Sat, 19 Nov 2022 21:54:08 +0000</pubDate>
      <link>https://dev.to/jungle_sven/5-ways-to-store-market-data-csv-sqlite-postgres-mongo-arctic-172c</link>
      <guid>https://dev.to/jungle_sven/5-ways-to-store-market-data-csv-sqlite-postgres-mongo-arctic-172c</guid>
      <description>&lt;p&gt;What’s the best way to store market data?&lt;/p&gt;

&lt;p&gt;Well, it depends on a combination of factors. Among the most important, I will name dataset size, read and write queries frequency, and desired latency. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Hyd17mn6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ddxvfa38mkd16mpqfuya.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Hyd17mn6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ddxvfa38mkd16mpqfuya.png" alt="types of data" width="880" height="491"&gt;&lt;/a&gt;&lt;br&gt;
 &lt;br&gt;
So let’s dive in and build an app to perform a considerable amount of CRUD operations and connect it to different databases. We will use plain CSV files, relational databases SQLite and Postgres, and non-relational databases Mongo and Arctic.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Jungle-Sven/efficient_trading_software/blob/main/5_data_storage.py"&gt;Github&lt;/a&gt; repo.&lt;/p&gt;

&lt;p&gt;We will measure the time of execution of the following operations:&lt;/p&gt;

&lt;p&gt;- append 1k records one by one,&lt;/p&gt;

&lt;p&gt;- bulk save 1M records,&lt;/p&gt;

&lt;p&gt;- read the entire database with 1M records,&lt;/p&gt;

&lt;p&gt;- make a single query to the database with 1M records&lt;/p&gt;

&lt;p&gt;We will also compare the database size of 1M records datasets.&lt;/p&gt;

&lt;p&gt;To produce that 1M records, we will use the synthetic data generator described &lt;a href="https://github.com/Jungle-Sven/efficient_trading_software/blob/main/synthetic_data_generator.py"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Oc1yg_tt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vjl3ybyiemnu423bmj34.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Oc1yg_tt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vjl3ybyiemnu423bmj34.jpg" alt="synthetic data generator" width="512" height="512"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s make an overview of possible data storage options. CSV files are a fast and comfortable way to work with spreadsheet data, but it’s not great as permanent data storage. SQLite needs no setup and is quick and stable – probably the best option for small projects. Postgres is an open-source production-ready database with lots of use cases. Mongo is a NoSQL alternative that can sometimes be much faster than SQL databases. Arctic is built upon Mongo to make it even more helpful for those who work with market data, as Arctic supports pandas dataframes and NumPy arrays by default. &lt;/p&gt;

&lt;p&gt;Now let’s talk about our &lt;strong&gt;app&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;We will create five connectors to five different data storages. They will consist of four classes: Connector, ReaderApp, WriterApp, and ServiceApp. This time, we will build some connectors from scratch instead of using SQLAlchemy for educational purposes.&lt;/p&gt;

&lt;p&gt;The connector class will contain service data like filenames and methods to create tables.&lt;/p&gt;

&lt;p&gt;ReaderApp will contain methods to read data from the database and to make a query.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class ReaderApp:
    __metaclass__ = ABCMeta

    @abstractmethod
    def read_all_data(self):
        '''reads all data from file/database'''
        raise NotImplementedError("Should implement read_all_data()")

    @abstractmethod
    def read_query(self):
        '''makes a specific query to file/database '''
        raise NotImplementedError("Should implement read_query()")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;WriterApp will save data to the database.&lt;br&gt;
&lt;br&gt;
 &lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class WriterApp:
    __metaclass__ = ABCMeta

    @abstractmethod
    def append_data(self):
        '''saves data line by line, like in real app '''
        raise NotImplementedError("Should implement save_data()")

    @abstractmethod
    def bulk_save_data(self):
        '''save all data at one time '''
        raise NotImplementedError("Should implement bulk_save_data()")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And ServiceApp will be responsible for clearing databases and statistics, including database size.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class ServiceApp:
    __metaclass__ = ABCMeta

    @abstractmethod
    def clear_database(self):
        raise NotImplementedError("Should implement clear_database()")

    @abstractmethod
    def size_of_database(self):
        raise NotImplementedError("Should implement size_of_database()")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After all those classes are built, we can use them in our main app, MultiDatabaseApp. It will generate synthetic data, perform CRUD operations, measure execution time, and plot charts to visualize results. &lt;/p&gt;

&lt;p&gt;The most pythonic way to measure execution time is to use a decorator function. It simply makes something before and after launching the ‘decorated’ part.&lt;br&gt;
&lt;br&gt;
 &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def execution_time(func):
        #measures a database operation execution time
        def measure_time(*args, **kwargs) -&amp;gt; dict:
            start_time = time.time()
            response = func(*args, **kwargs)
            execution_time = time.time() - start_time
            response['execution_time'] = execution_time
            return response
        return measure_time
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code is available &lt;a href="https://github.com/Jungle-Sven/efficient_trading_software"&gt;here&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Now all preparations are ready, and we can start!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--x-bd8hEk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hxv9wlzrvdok76kv1una.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--x-bd8hEk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hxv9wlzrvdok76kv1una.jpg" alt="testing start" width="512" height="512"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The first action is to bulk save 1 million synthetic ticks. Both Postgres and Mongo work slowly. All database server’s settings are default, which could be the reason. Arctic is the leader here!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6q3Gyc3B--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jtmlnn1rgol2xzzwhri1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6q3Gyc3B--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jtmlnn1rgol2xzzwhri1.png" alt="bulk save data" width="880" height="428"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Both CSV and SQLite are almost as fast as Arctic.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cO7md15q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6rv4h578cbr25rllt2ls.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cO7md15q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6rv4h578cbr25rllt2ls.png" alt="bulk save execution time" width="849" height="61"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The next test is appending 1000 ticks one by one. And again, Postgres is the worst option. Mongo is the leader here; we can choose it if we need to save data frequently. Arctic, built on Mongo, should have the same speed. Still, I was using VersionStore with 1 million already added data points, so Arctic reads that data each time, appends one, and saves. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--l6rOG86v--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/taa5mp8m1v6olxv3y99y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--l6rOG86v--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/taa5mp8m1v6olxv3y99y.png" alt="append data" width="880" height="428"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Both CSV and SQLite show decent results. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kbuvyRQm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l2v17pqmiptbh69p1y1p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kbuvyRQm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l2v17pqmiptbh69p1y1p.png" alt="append data execution time" width="826" height="54"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now let’s check the read operations speed. The first is just a query to read the whole dataset. CSV shows the best result. The operation is complete in less than 1 second! Postgres and Arctic need almost 2 seconds, SQLite – 3 seconds. Mongo is the slowest horse, with 7 seconds. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZPAm0vXd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/78f6qemtj50hqkudnxg5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZPAm0vXd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/78f6qemtj50hqkudnxg5.png" alt="read data" width="880" height="428"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JjnRnp1G--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zjvyx6wu19sef728d584.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JjnRnp1G--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zjvyx6wu19sef728d584.png" alt="read data execution time" width="796" height="58"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The next operation to test is a query to select only those rows where the Bitcoin price is less than 20155. SQL databases are fast enough, the same as CSV files. Mongo and Arctic need more time to get data from the database.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bMAQBhgo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4peq4xi26443y81tcvj2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bMAQBhgo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4peq4xi26443y81tcvj2.png" alt="read query" width="880" height="428"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NV-0E97N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4szcmb79s3bc7464zhhw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NV-0E97N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4szcmb79s3bc7464zhhw.png" alt="read query execution time" width="775" height="55"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now let’s check our database’s sizes. Arctic is at least two times better than any competitor. What a great result! CSV and SQLite databases are medium sizes, about 40Mb each. Postgres and Mongo need about 100Mb to store the same amount of data, which means that if we are limited with disk space or bandwidth usage, we have to consider other options. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Hr0HWm9p--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2wtcyqjlqgy133edu6i1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Hr0HWm9p--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2wtcyqjlqgy133edu6i1.png" alt="database size" width="880" height="428"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--j6ZkPh6e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0gywpv6upl9py539x539.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--j6ZkPh6e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0gywpv6upl9py539x539.png" alt="database size Mb" width="880" height="50"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now let’s have a look at creating operations execution time once more. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--j2Jg1b1V--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hzfqsj7kfdvotpzn5ccm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--j2Jg1b1V--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hzfqsj7kfdvotpzn5ccm.png" alt="add data operations" width="880" height="428"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Mongo and Arctic can be our choice if we have to perform many write operations on our database. But in fact, CSV and SQLite could be our choice too. Postgres is the slowest option, but there are ways to solve this, like sending async requests to a dedicated database server. &lt;/p&gt;

&lt;p&gt;Read operations combined. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--unycaBc6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q6jq49fleis49b1mqyob.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--unycaBc6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q6jq49fleis49b1mqyob.png" alt="read data operations" width="880" height="428"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Postgres looks like a good choice here. Of course, CSV files are even faster, but CSV is not an actual database. Arctic looks like an excellent option to take into consideration. Mongo is the slowest one. &lt;/p&gt;

&lt;p&gt;Some final thoughts. CSV and SQLite are not production-ready choices in many cases, but for a bunch of small/medium projects, they can be easy. Postgres has a slow write time, so it doesn’t look like an option for storing market data. Mongo and Arctic can be good options if we talk about a vast dataset that can not be stored in a plain CSV file. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Jungle-Sven/efficient_trading_software/blob/main/5_data_storage.py"&gt;Github&lt;/a&gt; repo with the code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xlsycFZX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0pcfz2vuvdbuxvv2llfy.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xlsycFZX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0pcfz2vuvdbuxvv2llfy.jpg" alt="testing finish" width="512" height="512"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  python #databases #sql #nosql #market-data
&lt;/h1&gt;

</description>
      <category>python</category>
      <category>database</category>
      <category>sql</category>
      <category>nosql</category>
    </item>
    <item>
      <title>What is market data and how to generate it with Python</title>
      <dc:creator>Jungle Sven</dc:creator>
      <pubDate>Fri, 28 Oct 2022 10:12:18 +0000</pubDate>
      <link>https://dev.to/jungle_sven/what-is-market-data-and-how-to-generate-it-with-python-e46</link>
      <guid>https://dev.to/jungle_sven/what-is-market-data-and-how-to-generate-it-with-python-e46</guid>
      <description>&lt;h5&gt;
  
  
  Abstract
&lt;/h5&gt;

&lt;p&gt;Our trading software is definitely going to consume some market data. The most straightforward way to use market data is by analyzing the market and producing some sort of signals for our trading system. But we can also gather a vast amount of data to further build analytical models, train ML algorithms, prepare reports, and more.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0DjjzlDl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p95evuumvv9frfp2maba.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0DjjzlDl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p95evuumvv9frfp2maba.png" alt="synthetic market data generated with Python" width="880" height="408"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Market data is often gathered from data providers, exchanges, and other sources. We will learn how to generate synthetic market data. Later we will receive data from external providers, and we will build a data storage system ourselves for educational purposes.  &lt;/p&gt;

&lt;h5&gt;
  
  
  What is market data
&lt;/h5&gt;

&lt;p&gt;Market data means prices in general. It consists of facts about an occurred trade: name of exchange, name of the asset, price, quantity, trade timestamp, and more. Now we will talk about the two most common types of market data: ohlcv and ticks.&lt;/p&gt;

&lt;h5&gt;
  
  
  OHLCV
&lt;/h5&gt;

&lt;p&gt;First of all, some definitions. OHLCV is market data combined into a block, it’s not really precise, but it gives traders a general understanding of what happened in the market.&lt;/p&gt;

&lt;p&gt;OHLCV corresponds to Open, High, Low, Close, Volume – this is information about trades closed during a period of time(e.g., 1 minute, 15 minutes, 1 hour, 1 day, etc.).&lt;/p&gt;

&lt;p&gt;For example, let us say we talk about BTC/USDT market; OHLCV data was gathered for one day period. During such a period, thousands of trades can be processed on large exchanges like Binance. OHLCV gives us only general information: first trade was at a price 19123$(O), the highest price during this period was 19347$(H), the lowest price was 18900$(L), the last price was 19041$(C ), and the sum of all trades during the period was 223500(V).&lt;/p&gt;

&lt;p&gt;And, of course, our data is marked with timestamps so we can easily understand when those trades were executed. In our example, data was gathered from October 22, 2021, to October 20, 2022.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Dx-iKmhH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ofpguoeqdkwdgg7c9550.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Dx-iKmhH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ofpguoeqdkwdgg7c9550.png" alt="OHLCV data example" width="867" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h5&gt;
  
  
  Ticks
&lt;/h5&gt;

&lt;p&gt;Tick data is information about each separate trade that happened in an exchange. Those who need more details about the market prefer tick data.&lt;/p&gt;

&lt;p&gt;In this example, we connected to DYDX decentralized exchange via WebSocket. Our tick data consists of a timestamp of each trade, symbol(e.g., BTC/USD), side(BUY or SELL) and amount(in BTC).  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DhQZXB6z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b27z4ovi8hscqfz8txr9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DhQZXB6z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b27z4ovi8hscqfz8txr9.png" alt="tick data example" width="880" height="127"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h5&gt;
  
  
  Synthetic data
&lt;/h5&gt;

&lt;p&gt;As our goal is to understand the pros and cons of different data consumption, storage, and manipulation approaches, we will need a lot of data. We will use synthetic data generation as it’s pretty easy to generate 10 or 10 million data samples with the same function.&lt;/p&gt;

&lt;p&gt;First of all, let’s define some basic data classes to work with.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class OHLCV:
    def __init__(self, timestamp, open, high, low, close, volume):
        self.timestamp = timestamp
        self.open = open
        self.high = high
        self.low = low
        self.close = close
        self.volume = volume
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Tick:
    def __init__(self, timestamp, symbol, side, amount, price, exchange):
        self.timestamp = timestamp
        self.symbol = symbol
        self.side = side
        self.amount = amount
        self.price = price
        self.exchange = exchange
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we will create one more class, DataSample. It will be used to generate synthetic data. We will implement 3 methods for now: &lt;br&gt;&lt;br&gt;
- generate() to generate a single data sample&lt;br&gt;&lt;br&gt;
- build() to generate datasets using generate function&lt;br&gt;&lt;br&gt;
- plot() to visualize our data&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class DataSample:
    def __init__(self):
        pass

    def generate(self):
        '''generates 1 data sample'''
        pass

    def build(self):
        '''builds a dataframe of data samples'''
        pass

    def plot(self):
        '''visualizes our dataset'''
        pass
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we will build 2 more classes – DataSampleOHLCV and DataSampleTicks. They both will have implemented methods generate, build and plot.&lt;/p&gt;

&lt;p&gt;Generate function will use Random library so our prices will look more natural. Each next generated price will be slightly different from the previos one.&lt;/p&gt;

&lt;p&gt;DataSampleOHLCV and DataSampleTicks code is available in my &lt;a href="https://github.com/Jungle-Sven/efficient_trading_software/blob/main/4_synthetic_data.py"&gt;GitHub&lt;/a&gt; repo.&lt;/p&gt;

&lt;p&gt;And, finally, one more thing – DataGenerator. It will utilize both DataSampleOHLCV and DataSampleTicks classes and will work as a single interface to generate synthetic data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class DataGenerator:
    def __init__(self):
        self.ticks = DataSampleTicks()
        self.ohlcv = DataSampleOHLCV()

    def run_ticks(self):
        data = self.ticks.build(n = 10000)
        self.ticks.plot(data)
        return data

    def run_ohlcv(self):
        data = self.ohlcv.build(n = 1000)
        self.ohlcv.plot(data)
        return data
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now lets run the code and see what happens!&lt;/p&gt;

&lt;p&gt;Generated OHLCV, 1k samples.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--enepN1SW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1l3wem089s25jwlj9i48.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--enepN1SW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1l3wem089s25jwlj9i48.png" alt="generated OHLCV data" width="880" height="428"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Generated tick data, 10k samples.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kM5lP8p5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6djfdtx7w2yylslip0fo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kM5lP8p5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6djfdtx7w2yylslip0fo.png" alt="generated tick data" width="880" height="428"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The code is available in my &lt;a href="https://github.com/Jungle-Sven/efficient_trading_software/blob/main/4_synthetic_data.py"&gt;GitHub&lt;/a&gt; repo.&lt;/p&gt;

</description>
      <category>python</category>
      <category>generateddata</category>
      <category>marketdata</category>
      <category>syntheticdata</category>
    </item>
    <item>
      <title>Microservices</title>
      <dc:creator>Jungle Sven</dc:creator>
      <pubDate>Fri, 21 Oct 2022 06:30:04 +0000</pubDate>
      <link>https://dev.to/jungle_sven/microservices-42o</link>
      <guid>https://dev.to/jungle_sven/microservices-42o</guid>
      <description>&lt;p&gt;Microservice software architecture is something opposite of monolithic architecture. For small projects, monolithic architecture is the most straightforward way to think about its design in general. But any mature project cannot be developed and supported easily if it is a monolith. &lt;/p&gt;

&lt;p&gt;The microservice pattern forces developers to divide the project not just into separate modules and classes but into individual tiny apps called microservices. They can be deployed in different data centers, supported by other teams, etc. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OlJN2fxo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rp8ho0eqzlcbsi8lck5l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OlJN2fxo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rp8ho0eqzlcbsi8lck5l.png" alt="Microservices" width="880" height="552"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we will build a simple microservice for our trading software. It will receive our order data via API and save it to the local database. Of course, it is possible to save that data to a local disk. Still, suppose we want to build high-frequency trading software. In that case, we don't want to waste any local resources on logging or statistics, or maybe we want to outsource the development of a feature to a different developers team.&lt;/p&gt;

&lt;p&gt;First of all, we will build a basic database connector. We will use the SQLite database for educational purposes. We will create a table of Orders containing six fields: timestamp, username, market, side, size, and price. &lt;/p&gt;

&lt;p&gt;Example code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Database:
    #this is a DB connector
    #we will use SQLite in this example for simplicity
    def init(self):
        #filename and path to the database are hardcoded for simplicity
        self.connect_to = 'test.db'
    def create_table_orders(self):
        #a func to create our database
        conn = sqlite3.connect(self.connect_to)
        conn.execute('''CREATE TABLE if not exists Orders
        (timestamp TEXT NOT NULL,
        username TEXT NOT NULL,
        market TEXT NOT NULL,
        side TEXT NOT NULL,
        size FLOAT NOT NULL,
        price FLOAT NOT NULL
        );''')
        conn.close()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Database connector will have only one method implemented to save order data to the database.&lt;/p&gt;

&lt;p&gt;Example code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def add_data_orders(self, timestamp, username, market, side, size, price):
    #a func to save orders data
    conn = sqlite3.connect(self.connect_to)
    conn.execute("INSERT INTO Orders (timestamp, username, market, side, size, price) VALUES (?, ?, ?, ?, ?, ?)", (timestamp,
    username, market, side, size, price));
    conn.commit()
    conn.close()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Second, we need an API server. Creating a simple API server with the Flask module in less than 30 lines of code is possible. It will be able to receive HTTP POST requests with order data and save it to the database.&lt;/p&gt;

&lt;p&gt;Example code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@app.post("/API/orders")
def save_orders():
    if request.is_json:
        response = request.get_json()
        DB.add_data_orders(response['timestamp'], response['username'], response['market'], response['side'],  
        response['size'], response['price'])
        return response, 201
        return {"error": "Request must be JSON"}, 415
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can find complete database connector code and API SERVER code on GitHub.&lt;/p&gt;

&lt;p&gt;And finally, we need an API connector for our service. Our API connector will use the requests library to make POST HTTP requests to our API server.&lt;/p&gt;

&lt;p&gt;Example code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def generate_request(self, order):
    try:
        response = requests.post(self.api_url, json=order)
        print(response)
    except Exception as e:
        print('generate_request - Exception', e)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can find the complete API CLIENT code on GitHub. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bvYeipwL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/il7eg43qx5j29h6p3wop.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bvYeipwL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/il7eg43qx5j29h6p3wop.png" alt="a tiny microservice app written in python" width="880" height="188"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In ~100 lines of code, we created a database connector, API server, and API client to save order data to the database on the remote server. &lt;/p&gt;

&lt;p&gt;The code is available in this &lt;a href="https://github.com/Jungle-Sven/efficient_trading_software/blob/main/3_microservices_server.py"&gt;Github repo&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>microservices</category>
      <category>python</category>
      <category>programming</category>
      <category>api</category>
    </item>
    <item>
      <title>Event-driven approach</title>
      <dc:creator>Jungle Sven</dc:creator>
      <pubDate>Mon, 17 Oct 2022 15:36:40 +0000</pubDate>
      <link>https://dev.to/jungle_sven/event-driven-approach-524f</link>
      <guid>https://dev.to/jungle_sven/event-driven-approach-524f</guid>
      <description>&lt;p&gt;The event-driven approach is a way to think about software architecture. Developing and maintaining a considerable trading application while thinking in procedures and functions paradigm could be inefficient and even impossible.&lt;/p&gt;

&lt;p&gt; &lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4tVnn1Tx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j8hosie18vffyx3em09y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4tVnn1Tx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j8hosie18vffyx3em09y.png" alt="event driven approach" width="256" height="256"&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;
 &lt;/p&gt;

&lt;p&gt;We can think about trading software as a system that reacts to some random events in the real world. Something happens in the market; prices change, which is an event. We can process it inside our system and produce another event, order, for example, it conditions are met. We can also create a logging or notification event based on our needs.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;The event-driven approach helps us better understand what is happening inside the system, maintain control, and support clearer and more efficient software architecture. &lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Events&lt;/strong&gt; are the fundamental element of our architecture. You can think of events as data classes or data structures. They can contain a lot of information like the event type, timestamp, specific data, etc.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Event(object):
    #base class
    pass
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;p&gt; &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class AccountUpdateEvent(Event):
    def __init__(self, timestamp, username, total):
        self.type = 'ACCOUNT_UPDATE'
        self.timestamp = timestamp
        self.username = username
        self.total = float(total)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we will build a simple application that can produce and process events in less than 100 lines of python code!&lt;/p&gt;

&lt;p&gt;Our first module is going to make API calls and produce events.&lt;/p&gt;

&lt;p&gt;Example code(whole class is available in &lt;a href="https://github.com/Jungle-Sven/efficient_trading_software/blob/main/2_event_driven_approach.py"&gt;my GitHub repo&lt;/a&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class GetAccountData:
    def create_event(self, timestamp, username, total):
        self.events.put(AccountUpdateEvent(timestamp=timestamp, username=username, total=total))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt; &lt;/p&gt;

&lt;p&gt;The second module processes events.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;Example code(whole class is available in &lt;a href="https://github.com/Jungle-Sven/efficient_trading_software/blob/main/2_event_driven_approach.py"&gt;my GitHub repo&lt;/a&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class ProcessAccountData:
    def update_account_data(self, event):
        print('Account update received at: ', event.timestamp, 'Username: ', event.username, 'Total balance: ', event.total)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And, finally, our app. It will contain both GetAccountData and ProcessAccountData and a queue of events.&lt;/p&gt;

&lt;p&gt;Example code(whole class is available in &lt;a href="https://github.com/Jungle-Sven/efficient_trading_software/blob/main/2_event_driven_approach.py"&gt;my GitHub repo&lt;/a&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class App:
    def __init__(self):
        self.events = Queue()
        self.get_data_account = GetAccountData(self.events)
        self.process_data_account = ProcessAccountData()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt; &lt;/p&gt;

&lt;p&gt;This app contains a &lt;strong&gt;loop&lt;/strong&gt; to process events. Once a new event is in our queue, we take it out and process it. &lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;Example code(whole class is available in &lt;a href="https://github.com/Jungle-Sven/efficient_trading_software/blob/main/2_event_driven_approach.py"&gt;my GitHub repo&lt;/a&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def event_loop(self):
       while True:
            try:
                event = self.events.get(False)
            except Exception as e:
                time.sleep(1)
                break

            else:
                try:
                    if event is not None:
                        if event.type == 'ACCOUNT_UPDATE':
                            self.process_data_account.update_account_data(event)

                except Exception as e:
                    print('event_loop error:', e)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RwOxDtff--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y5pnn4vs0wd1t1qyvqyq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RwOxDtff--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y5pnn4vs0wd1t1qyvqyq.png" alt="Event driven application" width="880" height="358"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;This is an example of a simple event-driven application. You can find the source code in &lt;a href="https://github.com/Jungle-Sven/efficient_trading_software/blob/main/2_event_driven_approach.py"&gt;my GitHub repo&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>eventdriven</category>
      <category>python</category>
      <category>trading</category>
      <category>programming</category>
    </item>
    <item>
      <title>Asynchronous programming</title>
      <dc:creator>Jungle Sven</dc:creator>
      <pubDate>Fri, 14 Oct 2022 06:35:21 +0000</pubDate>
      <link>https://dev.to/jungle_sven/asynchronous-programming-4353</link>
      <guid>https://dev.to/jungle_sven/asynchronous-programming-4353</guid>
      <description>&lt;p&gt;It would be best if you had at least a basic understanding of asynchronous programming to build fast-reacting trading software. &lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;The problem with the synchronous approach used most of the time is that our program must wait for data input from dedicated sources before proceeding to further actions. Connecting to WebSockets and receiving tick data updates or open order updates from exchanges using synchronous software is nearly impossible. &lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;Asynchronous programming allows us to skip waiting for data input and proceed to the control stream or data processing stream. This approach radically improves our software speed and performance.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fPb5ETiU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uwgc8qtucot8l7kuwoyi.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fPb5ETiU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uwgc8qtucot8l7kuwoyi.jpg" alt="Image description" width="750" height="500"&gt;&lt;/a&gt;&lt;br&gt;
 &lt;/p&gt;

&lt;p&gt;We will use &lt;a href="https://docs.python.org/3/library/asyncio.html"&gt;asyncio&lt;/a&gt; python library for building an asynchronous application.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;We need to learn a few concepts to start building asynchronous software.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;First, our functions are marked as asynchronous with &lt;strong&gt;async&lt;/strong&gt; word, like in JavaScript. Example:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;async def my_function()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt; &lt;/p&gt;

&lt;p&gt;Second, we use &lt;strong&gt;await&lt;/strong&gt; word to tell the program where it can switch control from one stream to another. Example:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;await asyncio.sleep(0)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt; &lt;/p&gt;

&lt;p&gt;This line of code does nothing but tell our program not to wait for data input or some long calculations, so our program can switch to another task.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;Third, in building asynchronous software, we operate not only functions but &lt;strong&gt;tasks&lt;/strong&gt;. A task can contain one or more functions inside.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;async def input_func():
    pass


async def input_task():
    await asyncio.sleep(0)
    await self.input_func()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt; &lt;/p&gt;

&lt;p&gt;And, finally, &lt;strong&gt;loops&lt;/strong&gt;. Our tasks are run inside loops, which can be called ‘control streams’. &lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ioloop = asyncio.get_event_loop()
tasks = [ioloop.create_task(input_task()), ioloop.create_task(another_task())]
wait_tasks = asyncio.wait(tasks)
ioloop.run_until_complete(wait_tasks)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mf7JISNf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x8suj0kcd63i22g3cada.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mf7JISNf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x8suj0kcd63i22g3cada.png" alt="Image description" width="493" height="508"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is an example of a simple asynchronous application. You can find it in &lt;a href="https://github.com/Jungle-Sven/efficient_trading_software/blob/main/1_asynchronous_programming.py"&gt;this GitHub repo&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>python</category>
      <category>asyncio</category>
      <category>software</category>
      <category>programming</category>
    </item>
    <item>
      <title>Building efficient crypto trading software with python</title>
      <dc:creator>Jungle Sven</dc:creator>
      <pubDate>Tue, 11 Oct 2022 09:12:05 +0000</pubDate>
      <link>https://dev.to/jungle_sven/building-efficient-crypto-trading-software-with-python-8o2</link>
      <guid>https://dev.to/jungle_sven/building-efficient-crypto-trading-software-with-python-8o2</guid>
      <description>&lt;p&gt;Hello and welcome to this short list of articles where I will talk about the modern approach to building production-grade trading software with python programming language.&lt;/p&gt;

&lt;p&gt;Python is widely used for its simplicity and clean, readable code. More than one million software developers can understand and support the code written in python.&lt;/p&gt;

&lt;p&gt;But python is known for some disadvantages, such as speed. You can ignore this disadvantage most of the time as most libraries used for trading purposes use code snippets written in C and are fast enough for most common tasks.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Xg6pNv1M--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/67obl0md1tgi210zctel.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Xg6pNv1M--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/67obl0md1tgi210zctel.png" alt="Image description" width="880" height="464"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We will discuss three main concepts: asynchronous programming, event-driven architecture, and microservices architecture.&lt;/p&gt;

&lt;p&gt;As far as our software will use different data sources, API services, and more, we will have to make it asynchronous, so we will not wait for a data lag from any remote services. Asynchronous execution is a must.&lt;/p&gt;

&lt;p&gt;The event-driven approach helps us better understand and control what is happening in the system, which works fast. &lt;/p&gt;

&lt;p&gt;Microservices architecture makes it easier to develop and support projects with thousands of lines of code by giving us a chance to focus on a single problem which can be way harder with a monolithic architecture.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3XceI22a--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4dt9qxr2s2vflrfu1swe.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3XceI22a--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4dt9qxr2s2vflrfu1swe.jpg" alt="Image description" width="880" height="880"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you are interested in learning about building crypto trading software, follow this channel for more content.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>trading</category>
      <category>python</category>
    </item>
  </channel>
</rss>
