<?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: Suleyman Sade</title>
    <description>The latest articles on DEV Community by Suleyman Sade (@suleyman_sade).</description>
    <link>https://dev.to/suleyman_sade</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%2F1667595%2F52a2abb6-2ade-4e47-a908-68bdb8984641.jpg</url>
      <title>DEV Community: Suleyman Sade</title>
      <link>https://dev.to/suleyman_sade</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/suleyman_sade"/>
    <language>en</language>
    <item>
      <title>When the Market Takes Weekends Off - Devlog Stocksimpy</title>
      <dc:creator>Suleyman Sade</dc:creator>
      <pubDate>Fri, 31 Oct 2025 22:37:03 +0000</pubDate>
      <link>https://dev.to/suleyman_sade/when-the-market-takes-weekends-off-devlog-stocksimpy-2c2b</link>
      <guid>https://dev.to/suleyman_sade/when-the-market-takes-weekends-off-devlog-stocksimpy-2c2b</guid>
      <description>&lt;p&gt;I recently took a long break from working on StockSimPy — school got busy and pulled me away — but I’m back. The project is getting closer to the finish line, yet somehow the closer I get, the further it feels. The core components — backtesting, portfolio management, and stock data handling — are semi-functional, but parts like importing data from &lt;code&gt;yfinance&lt;/code&gt; and cleaning it still need fixes, along with a few unexpected bugs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Add Performance Metrics?
&lt;/h2&gt;

&lt;p&gt;When I first planned StockSimPy, I didn’t think about including a dedicated performance class. I figured total return and a price graph would be enough. That changed after someone commented on one of my previous devlogs, asking if I planned to add metrics like the Sortino ratio.&lt;/p&gt;

&lt;p&gt;That question stuck with me. I thought: &lt;em&gt;If I were someone testing a trading strategy, would I want performance metrics?&lt;/em&gt; The answer was obviously &lt;strong&gt;yes&lt;/strong&gt;. So, I researched what to include. For the initial release, I wanted just enough metrics to make the analysis meaningful without overcomplicating it. I settled on three: &lt;strong&gt;volatility&lt;/strong&gt;, &lt;strong&gt;Sharpe ratio&lt;/strong&gt;, and &lt;strong&gt;maximum drawdown&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This was my first time implementing these metrics, so I kept things simple — but not everything went smoothly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Challenge #1: Counting Days
&lt;/h2&gt;

&lt;p&gt;The stock market isn’t open every day. There are weekends, federal holidays, and random closures, which complicate calculating metrics like the Sharpe ratio and annualized return. I initially assumed that &lt;code&gt;yfinance&lt;/code&gt; data only included trading days, but I needed to confirm how many actual trading days the backtest covered.&lt;/p&gt;

&lt;p&gt;Then it hit me: my DataFrame already contained the portfolio value for each recorded date. By subtracting the first date from the last, I could find the total number of days in the simulation. From there, it was straightforward to plug that into the formula for annualized return. (I used an &lt;a href="https://www.investopedia.com/terms/a/annualized-total-return.asp" rel="noopener noreferrer"&gt;external resource&lt;/a&gt; for the math.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Challenge #2: AI Boundaries
&lt;/h2&gt;

&lt;p&gt;I didn’t want StockSimPy to turn into a “vibe-coded” AI-assisted project. My rule was to only use AI for &lt;strong&gt;documentation&lt;/strong&gt;, &lt;strong&gt;examples&lt;/strong&gt;, and &lt;strong&gt;code formatting&lt;/strong&gt;. At first, that worked great — it helped generate detailed documentation and catch small formatting inconsistencies. But after a while, I noticed my calculations were returning wrong results. Turns out, the AI reformatted some logic incorrectly. Luckily, I had staged my changes beforehand, so rolling back was painless.&lt;/p&gt;

&lt;h2&gt;
  
  
  Challenge #3: Confirming the Accuracy of the Results
&lt;/h2&gt;

&lt;p&gt;To do this, I chose some stocks and checked their data on these performance metrics for the 1Y range. Then I ran my backtesting for 1Y, buying as many stocks as possible on &lt;strong&gt;day 1&lt;/strong&gt; — emphasis on &lt;em&gt;day 1&lt;/em&gt;. Most of the data was close enough, except for the &lt;strong&gt;total return&lt;/strong&gt;, which differed by about 10% in some extreme cases.&lt;/p&gt;

&lt;p&gt;I tried to figure out what was going wrong, and it turns out my code was running the backtest for &lt;strong&gt;364 days&lt;/strong&gt; instead of a full year. The initial date when all the stock was bought was on a &lt;strong&gt;Monday&lt;/strong&gt;, meaning there was a decent price difference between that Monday and the previous &lt;strong&gt;Friday&lt;/strong&gt;, which caused a surprisingly large difference once it was compounded over the entire year.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Overall, these challenges taught me that the accuracy of a finance project isn’t about the code, but the tiny assumptions buried in the data. With every print statement that I used to debug and fix errors, stocksimpy gets closer to being a reliable tool. There is still a lot more to develop…&lt;/p&gt;




&lt;p&gt;If there is anything you want me to add, or any suggestions. Please reach out to me on my socials, or comment below 👇. It really helps with improving the library.&lt;/p&gt;

&lt;p&gt;If you would like to support me:&lt;/p&gt;

&lt;p&gt;⭐ Star stocksimpy on &lt;a href="https://github.com/SuleymanSade/StockSimPy" rel="noopener noreferrer"&gt;Github&lt;/a&gt;&lt;br&gt;
📰 Read more of my posts on &lt;a href="https://medium.com/@suleymansade09" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;&lt;br&gt;
💬 Let’s connect on &lt;a href="https://www.linkedin.com/in/suleymansade/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;br&gt;
📱 And on &lt;a href="https://www.instagram.com/suleymansade.blog" rel="noopener noreferrer"&gt;Instagram&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thanks for reading. Let me know what else you would suggest I add before the initial release.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>opensource</category>
      <category>performance</category>
      <category>learning</category>
    </item>
    <item>
      <title>Understanding and Coding a Swerve Module in FRC</title>
      <dc:creator>Suleyman Sade</dc:creator>
      <pubDate>Sun, 19 Oct 2025 04:02:21 +0000</pubDate>
      <link>https://dev.to/suleyman_sade/understanding-and-coding-a-swerve-module-in-frc-342m</link>
      <guid>https://dev.to/suleyman_sade/understanding-and-coding-a-swerve-module-in-frc-342m</guid>
      <description>&lt;p&gt;Swerve drive is one of the most flexible and rewarding drivetrain systems in FRC. It allows your robot to move in any direction — forward, sideways, diagonally — while keeping its orientation fixed or rotating independently. That control comes at the cost of complexity: four independently steered modules, each with its own motor pair, encoder, and PID logic.&lt;/p&gt;

&lt;p&gt;In this post, we’ll walk through the foundation of a &lt;strong&gt;swerve module implementation in WPILib using CTRE’s Phoenix 6 API&lt;/strong&gt;. By the end, you should understand not only &lt;em&gt;how&lt;/em&gt; to code a swerve module, but &lt;em&gt;why&lt;/em&gt; each piece matters. This article is written both for rookie programmers and experienced teams who want a clean, modular reference.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Idea Behind Swerve
&lt;/h3&gt;

&lt;p&gt;A traditional tank drive uses two sides of motors: one for the left, one for the right. To turn, one side spins faster than the other. This works well, but it means your robot can’t move sideways without turning first.&lt;/p&gt;

&lt;p&gt;Swerve drive changes that completely. Instead of linking wheels in pairs, &lt;strong&gt;each wheel (or module)&lt;/strong&gt; can rotate independently to face any direction and drive at any speed.&lt;/p&gt;

&lt;p&gt;So what does that enable?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The robot can move &lt;strong&gt;in any direction&lt;/strong&gt; instantly — forwards, sideways, diagonally.&lt;/li&gt;
&lt;li&gt;It can &lt;strong&gt;rotate and translate at the same time&lt;/strong&gt;, something impossible in tank drive.&lt;/li&gt;
&lt;li&gt;It makes autonomous paths smoother and more efficient, since motion is continuous rather than segmented.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Mathematically, this is made possible by &lt;em&gt;vector addition.&lt;/em&gt; Each wheel’s motion contributes a velocity vector. By combining all four vectors, the robot can produce any movement it wants — translation, rotation, or both simultaneously.&lt;/p&gt;

&lt;p&gt;Each swerve module contains the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Turning motor&lt;/li&gt;
&lt;li&gt;Driving motor&lt;/li&gt;
&lt;li&gt;External encoder&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It makes a movement like this possible:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyodlvaq41tgo8idcfmcx.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyodlvaq41tgo8idcfmcx.gif" alt="Swerve module movement" width="645" height="538"&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;em&gt;Screen recorded from &lt;a href="https://pathplanner.dev/home.html" rel="noopener noreferrer"&gt;PathPlanner&lt;/a&gt; GUI&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Defining Constants
&lt;/h2&gt;

&lt;p&gt;Before writing any logic, we define our constants. These govern tuning parameters, motor calibration, and physical conversions. Keeping them centralized makes it easier to iterate later.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Constants&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;kPModuleTurningController&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;kPModuleDriveController&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;kMaxSpeedMetersPerSecond&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;4.0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// TODO: 'EncoderDistancePerPulse' should be calculated based on the gearing and wheel diameter&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;kDriveEncoderDistancePerPulse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0011265396&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; 

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="no"&gt;CAN_BUS_NAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"CANivore"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;kPModuleTurningController&lt;/code&gt;: Controls how aggressively the module turns toward its target angle.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;kPModuleDriveController&lt;/code&gt;: Starts at zero; increase later when tuning drive responsiveness.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;kDriveEncoderDistancePerPulse&lt;/code&gt; constant translates motor encoder readings into meters or inches traveled, you can change the units you use by changing this constant too — just try to keep everything consistent. You’ll need to calculate this using your wheel diameter and gear reduction.&lt;/p&gt;

&lt;p&gt;Finally, specifying the CAN bus name (“CANivore” in this example) helps WPILib locate your devices if you use multiple buses. If you are not using any additional CAN bus and directly connect it to roborio you don’t need this constant.&lt;/p&gt;

&lt;h2&gt;
  
  
  Constructing the Swerve Module
&lt;/h2&gt;

&lt;p&gt;Now we move into the &lt;code&gt;SwerveModule&lt;/code&gt; class, which is what we will use for the rest of the tutorial. There are 4 swerve modules in each robot, so we wanted to have a unified way of controlling these motors. &lt;code&gt;SwerveModule&lt;/code&gt; class allows just that.&lt;/p&gt;

&lt;p&gt;Here is the field of the class where we initialize our core motors and controllers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SwerveModule&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;TalonFX&lt;/span&gt; &lt;span class="n"&gt;m_driveMotor&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;TalonFX&lt;/span&gt; &lt;span class="n"&gt;m_turningMotor&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;AnalogInput&lt;/span&gt; &lt;span class="n"&gt;m_turningEncoderInput&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;turningMotorOffsetRadians&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;m_driveMotorGain&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;PIDController&lt;/span&gt; &lt;span class="n"&gt;m_drivePIDController&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
      &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PIDController&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Constants&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;kPModuleDriveController&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;PIDController&lt;/span&gt; &lt;span class="n"&gt;m_turningPIDController&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
      &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PIDController&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Constants&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;kPModuleTurningController&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.0001&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We first set our two motors — one for forward/backward and one for turning. In our case, these are TalonFX, but it is also possible to use SparkMax or other motors by changing some of the code. &lt;code&gt;AnalogInput&lt;/code&gt; is used as the encoder; it is an external encoder, not the built-in encoder — more on that later in the post.&lt;/p&gt;

&lt;p&gt;Then the &lt;code&gt;turningMotorOffsetRadians&lt;/code&gt; and &lt;code&gt;m_driveMotorGain&lt;/code&gt; are both values that need to be tuned to actually make the front of the robot front — eg, the 0 degrees of the swerve module might be facing some diagonal direction, so we want to add an offset to zero it to the direction that we desire.&lt;/p&gt;

&lt;p&gt;PIDController for driving is more about improving accuracy and having a smoother drive; however, it is not required. On the other hand, the &lt;code&gt;PIDConstroller&lt;/code&gt; for turning is something you need to use and fine-tune to get better results in rotation, which would significantly impact the speed of the robot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Initialization and Setup
&lt;/h2&gt;

&lt;p&gt;Inside the constructor, we initialize hardware and configure basic parameters:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;SwerveModule&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
      &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;driveMotorChannel&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
      &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;turningMotorChannel&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
      &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;analogEncoderPort&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
      &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;turningMotorOffsetRadians&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
      &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;driveMotorGain&lt;/span&gt;
      &lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="n"&gt;m_driveMotor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TalonFX&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;driveMotorChannel&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CANBus&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Constants&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;CAN_BUS_NAME&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="n"&gt;m_turningMotor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TalonFX&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;turningMotorChannel&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;  &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CANBus&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Constants&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;CAN_BUS_NAME&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;

    &lt;span class="n"&gt;m_driveMotor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setNeutralMode&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;NeutralModeValue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Brake&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;m_turningMotor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setNeutralMode&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;NeutralModeValue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Brake&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;turningMotorOffsetRadians&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;turningMotorOffsetRadians&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;m_driveMotorGain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;driveMotorGain&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;m_turningEncoderInput&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AnalogInput&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;analogEncoderPort&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;m_turningPIDController&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;enableContinuousInput&lt;/span&gt;&lt;span class="o"&gt;(-&lt;/span&gt;&lt;span class="nc"&gt;Math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;PI&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;PI&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We start off by initializing our two motors — again, you may not need the second parameter if you are directly connecting the motors to RoboRio.&lt;/p&gt;

&lt;p&gt;We set the mode of both motors to &lt;code&gt;Brake&lt;/code&gt; as we want to be able to quickly change direction and move.&lt;/p&gt;

&lt;p&gt;We set the tuning variables to the parameters. And initialize the encoder input with the given port.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why enableContinuousInput() Matters
&lt;/h2&gt;

&lt;p&gt;A PID controller normally drives the error between the current and target values. Without continuous input, going from 0° to 360° would make the motor rotate a full revolution — even though those angles are equivalent.&lt;/p&gt;

&lt;p&gt;By calling:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;m_turningPIDController&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;enableContinuousInput&lt;/span&gt;&lt;span class="o"&gt;(-&lt;/span&gt;&lt;span class="nc"&gt;Math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;PI&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;PI&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We tell the controller that &lt;code&gt;-π&lt;/code&gt; and &lt;code&gt;π&lt;/code&gt; represent the same point, allowing it to take the &lt;em&gt;shortest&lt;/em&gt; path between two angles.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiipgo27kz7icfxe7mirj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiipgo27kz7icfxe7mirj.png" alt="PID continuous input" width="541" height="301"&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;em&gt;Left is how the PID views the value before continuous input, and right is how it views the values after continuous input.&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; WPILib’s &lt;code&gt;SwerveModuleState&lt;/code&gt; also uses radians, so keeping everything in radians avoids unnecessary conversions and rounding errors.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Getting the Module’s State
&lt;/h2&gt;

&lt;p&gt;Before commanding motion, you need a way to know what each module is doing right now — its &lt;strong&gt;current wheel angle&lt;/strong&gt; and &lt;strong&gt;drive velocity&lt;/strong&gt;. That’s where the following helper methods come in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;SwerveModuleState&lt;/span&gt; &lt;span class="nf"&gt;getState&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SwerveModuleState&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;m_driveMotor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getVelocity&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getValueAsDouble&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Rotation2d&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;getTurningEncoderRadians&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
    &lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;SwerveModulePosition&lt;/span&gt; &lt;span class="nf"&gt;getPosition&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SwerveModulePosition&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;m_driveMotor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getPosition&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getValueAsDouble&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nc"&gt;Constants&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;kDriveEncoderDistancePerPulse&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Rotation2d&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;getTurningEncoderRadians&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
    &lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;getState()&lt;/code&gt; returns the &lt;strong&gt;instantaneous velocity and orientation&lt;/strong&gt; of the wheel — this is what the kinematics class uses to estimate robot motion in real time.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;getPosition()&lt;/code&gt; reports the &lt;strong&gt;total distance traveled&lt;/strong&gt; and current orientation, which odometry uses for tracking the robot’s pose across the field.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;See how both of them use &lt;code&gt;getTurningEncoderRadians()&lt;/code&gt; which converts the analog voltage from the encoder into a meaningful angle:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="nf"&gt;getTurningEncoderRadians&lt;/span&gt;&lt;span class="o"&gt;(){&lt;/span&gt;
    &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;angle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m_turningEncoderInput&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getVoltage&lt;/span&gt;&lt;span class="o"&gt;()/&lt;/span&gt;&lt;span class="nc"&gt;RobotController&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getVoltage5V&lt;/span&gt;&lt;span class="o"&gt;()))&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;2.0&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nc"&gt;Math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;PI&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;turningMotorOffsetRadians&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;angle&lt;/span&gt; &lt;span class="o"&gt;%=&lt;/span&gt; &lt;span class="mf"&gt;2.0&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nc"&gt;Math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;PI&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;angle&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;angle&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mf"&gt;2.0&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nc"&gt;Math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;PI&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;angle&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To summarize, the encoder returns a value — in volts — between 0V and 5V. We can use this to map out a full rotation, as there is a linear relationship between encoder value and the angle. We can divide this encoder value by 5V to get a range 0–1, and that would correspond to 0–2pi rad. So we just multiply it by 2pi and add &lt;code&gt;turningMotorOffsetRadians&lt;/code&gt;, depending on the front of the robot and the zero position of the encoder.&lt;/p&gt;

&lt;p&gt;An important note here is that subtracting from 1 in the equation depends on the placement of the encoder, so you may want to see if the change in angle makes sense and if it is reversed, just remove “1 -”.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg6lz9jt9rbjz09etjzyg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg6lz9jt9rbjz09etjzyg.png" alt="Encoder angle calculation" width="668" height="162"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Commanding the Module — &lt;code&gt;setDesiredState()&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;This is the core function of your &lt;code&gt;SwerveModule&lt;/code&gt; class. It takes in a target velocity and angle (from WPILib’s &lt;code&gt;SwerveModuleState&lt;/code&gt;) and drives the motors to achieve that.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setDesiredState&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SwerveModuleState&lt;/span&gt; &lt;span class="n"&gt;desiredState&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;SwerveModuleState&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;desiredState&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Prevent jittering at very low speeds&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;abs&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;speedMetersPerSecond&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;0.001&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;stop&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;optimize&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Rotation2d&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;getTurningEncoderRadians&lt;/span&gt;&lt;span class="o"&gt;()));&lt;/span&gt;

    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;driveOutput&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;m_drivePIDController&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;calculate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;m_driveMotor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getVelocity&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getValueAsDouble&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;
        &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;speedMetersPerSecond&lt;/span&gt;
    &lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;driveFeedForward&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;speedMetersPerSecond&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nc"&gt;Constants&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;kMaxSpeedMetersPerSecond&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;turnOutput&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;m_turningPIDController&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;calculate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;getTurningEncoderRadians&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;
        &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;angle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getRadians&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;m_driveMotor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="nc"&gt;MathUtil&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;clamp&lt;/span&gt;&lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="n"&gt;driveOutput&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;driveFeedForward&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;m_driveMotorGain&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;m_turningMotor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;turnOutput&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s unpack this:&lt;/p&gt;

&lt;h3&gt;
  
  
  Preventing Jitter
&lt;/h3&gt;

&lt;p&gt;When the desired speed is extremely small (less than 0.1% of full power), the module shouldn’t bother rotating to match a new angle. That would only cause the wheel to twitch in place.&lt;br&gt;&lt;br&gt;
So we check:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;abs&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;speedMetersPerSecond&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;0.001&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;stop&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This line saves wear on your steering motor and reduces noise when the robot is idle.&lt;/p&gt;

&lt;h3&gt;
  
  
  Optimizing the Wheel Angle
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;optimize&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Rotation2d&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;getTurningEncoderRadians&lt;/span&gt;&lt;span class="o"&gt;()));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;SwerveModuleState.optimize()&lt;/code&gt; ensures the module takes the &lt;em&gt;shortest&lt;/em&gt; way to reach the target direction. For example, instead of rotating 270°, it might flip the wheel 90° and reverse drive direction — same motion, faster response.&lt;/p&gt;

&lt;p&gt;See the illustration below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbquw66n5cu4gikmep0j0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbquw66n5cu4gikmep0j0.png" alt="Wheel angle optimization" width="767" height="352"&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;em&gt;Illustration on the left rotates more compared to the right illustration to be in the same position.&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Drive Output Calculation
&lt;/h3&gt;

&lt;p&gt;The drive motor’s control has two parts:&lt;/p&gt;

&lt;p&gt;First, PID drives the motor to the target speed by using the previously defined proportional, integral, and derivative values. (&lt;a href="https://frcdocs.wpi.edu/en/latest/docs/software/advanced-controls/introduction/pid-video.html" rel="noopener noreferrer"&gt;See more on how PID works&lt;/a&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;m_drivePIDController&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;calculate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;currentVelocity&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;targetVelocity&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we use feedforward to keep the wheel moving at the same velocity:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;speedMetersPerSecond&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nc"&gt;Constants&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;kMaxSpeedMetersPerSecond&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both are combined, scaled by &lt;code&gt;m_driveMotorGain&lt;/code&gt;, and clamped between -1 and 1 (full reverse to full forward).&lt;/p&gt;

&lt;h3&gt;
  
  
  Turning Output Calculation
&lt;/h3&gt;

&lt;p&gt;Turning is entirely handled by the PID controller:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;turnOutput&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;m_turningPIDController&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;calculate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;getTurningEncoderRadians&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;angle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getRadians&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This minimizes angular error between the current and target direction. Because we previously enabled continuous input, it always takes the shortest path across the ±π boundary.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting Motor Outputs
&lt;/h3&gt;

&lt;p&gt;Finally, we command the motors:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;m_driveMotor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="nc"&gt;MathUtil&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;clamp&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
            &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;driveOutput&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;driveFeedForward&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;m_driveMotorGain&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
             &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// min -100%&lt;/span&gt;
             &lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// max +100%&lt;/span&gt;
    &lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;m_turningMotor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;turnOutput&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, each module runs semi-independently: it continuously reads its encoder, calculates new outputs, and steers to the desired state.&lt;/p&gt;

&lt;h2&gt;
  
  
  Putting It All Together
&lt;/h2&gt;

&lt;p&gt;With &lt;code&gt;SwerveModule&lt;/code&gt; complete, you can now instantiate four of them in a drivetrain subsystem:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;SwerveModule&lt;/span&gt; &lt;span class="n"&gt;frontLeft&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SwerveModule&lt;/span&gt;&lt;span class="o"&gt;(...);&lt;/span&gt;
&lt;span class="nc"&gt;SwerveModule&lt;/span&gt; &lt;span class="n"&gt;frontRight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SwerveModule&lt;/span&gt;&lt;span class="o"&gt;(...);&lt;/span&gt;
&lt;span class="nc"&gt;SwerveModule&lt;/span&gt; &lt;span class="n"&gt;backLeft&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SwerveModule&lt;/span&gt;&lt;span class="o"&gt;(...);&lt;/span&gt;
&lt;span class="nc"&gt;SwerveModule&lt;/span&gt; &lt;span class="n"&gt;backRight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SwerveModule&lt;/span&gt;&lt;span class="o"&gt;(...);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, using &lt;code&gt;SwerveDriveKinematics&lt;/code&gt;, combine their states into a robot-level motion command. WPILib’s kinematics and odometry classes handle the math — your &lt;code&gt;SwerveModule&lt;/code&gt; executes per-wheel control.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next Steps:
&lt;/h2&gt;

&lt;p&gt;After this point, you need to perform the calculations to enable these separate modules to work together in moving the robot. This could be done in a wide variety of ways, depending on how you want to organize everything, but just make sure to keep your units consistent.&lt;/p&gt;

&lt;p&gt;You can watch &lt;a href="https://youtu.be/0Xi9yb1IMyA" rel="noopener noreferrer"&gt;this video&lt;/a&gt; to go deeper into swerve drive and how to code it.&lt;/p&gt;

&lt;p&gt;Here is the complete code of the &lt;code&gt;SwerveModule&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/SuleymanSade/SwerveDriveBase?source=post_page-----6dc48ee97300---------------------------------------" rel="noopener noreferrer"&gt;GitHub - SuleymanSade/SwerveDriveBase&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I write about learning AI by &lt;strong&gt;building real tools&lt;/strong&gt;, not just tutorials.&lt;/p&gt;




&lt;p&gt;I write more tutorials, personal thoughts and development stories on my blogs you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;📰 Read more of my posts on &lt;a href="https://medium.com/@suleymansade09" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;💬 Let’s connect on &lt;a href="https://www.linkedin.com/in/suleymansade/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks for reading — let me know if you’d like to collaborate on projects similar to these or have any questions.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>robotics</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>When a For Loop Powers Your Stock Backtester - Devlog</title>
      <dc:creator>Suleyman Sade</dc:creator>
      <pubDate>Wed, 10 Sep 2025 03:40:31 +0000</pubDate>
      <link>https://dev.to/suleyman_sade/when-a-for-loop-powers-your-stock-backtester-devlog-15ad</link>
      <guid>https://dev.to/suleyman_sade/when-a-for-loop-powers-your-stock-backtester-devlog-15ad</guid>
      <description>&lt;h2&gt;
  
  
  Yeah, you heard that right.
&lt;/h2&gt;

&lt;p&gt;This is part 6 of my &lt;em&gt;&lt;a href="https://medium.com/@suleymansade09/list/building-stocksimpy-944f16d39f68" rel="noopener noreferrer"&gt;Building Stocksimpy&lt;/a&gt;&lt;/em&gt; series, where I build a light-weight Python backtesting library, sharing every step along the way.&lt;/p&gt;

&lt;p&gt;In the last post, I explained why I created &lt;code&gt;Portfolio&lt;/code&gt; class: to keep everything organised and divide the load between classes. &lt;code&gt;Portfolio&lt;/code&gt; supports the main backtesting loop, which is what I’ll dive into today.&lt;/p&gt;




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

&lt;p&gt;&lt;code&gt;Backtester&lt;/code&gt; class is simple by design, and it should be. The &lt;code&gt;strategy&lt;/code&gt; —deciding whether to buy or sell — is provided when the class is initialized. My initial thought was to have &lt;code&gt;strategy&lt;/code&gt; as a simple function returning &lt;code&gt;buy&lt;/code&gt;, &lt;code&gt;sell&lt;/code&gt;, or &lt;code&gt;hold&lt;/code&gt;. And that's the way it works in the code right now.&lt;/p&gt;

&lt;p&gt;However, some strategies may require multiple calculations and calling a bunch of different functions to calculate whether it is worth selling or not. So I might pivot to allowing either a function or a class. And if it is a class, I can decide on a &lt;code&gt;signal_generator()&lt;/code&gt; that can still be used to generate the signal.&lt;/p&gt;

&lt;p&gt;This approach offers more flexibility, but since I am keeping things relatively lightweight, I will revisit this in the future.&lt;/p&gt;




&lt;h2&gt;
  
  
  Main Loop
&lt;/h2&gt;

&lt;p&gt;The core loop is literally a simple &lt;code&gt;for&lt;/code&gt; loop iterating over the length of the data. At first, I worried about performance — would processing large datasets take forever? Running 5–10 years of daily data took about 2 minutes on my machine, which is acceptable for a fully Python implementation.&lt;/p&gt;

&lt;p&gt;High-performance backtesting libraries often rely on C/C++ and create Python bindings. So I wasn’t expecting a performance similar to those top libraries, but still, it shouldn’t take hours to complete.&lt;/p&gt;

&lt;p&gt;But something I didn’t look too much into was &lt;code&gt;Pandas&lt;/code&gt; built-in functions. I could’ve used &lt;code&gt;strategy&lt;/code&gt; to precompute signals beforehand and storing them in a &lt;code&gt;Pandas.Series.&lt;/code&gt; Then I could run a for loop for the dates where there is a trade. This would have been much more efficient, and I might implement it in the future.&lt;/p&gt;




&lt;h2&gt;
  
  
  Fixed vs. Dynamic Backtesting
&lt;/h2&gt;

&lt;p&gt;I’ve built two &lt;code&gt;run_backtest()&lt;/code&gt; functions to run it. Why? I wanted to keep things simple while also offering flexibility. I wanted to allow users to just trade a fix amount. But then I realised this can get very limiting, even for simple testing purposes.&lt;/p&gt;

&lt;p&gt;I wanted to write a strategy that sells half of the owned stock tied to a logic, but this was not possible by only getting a signal. So I created &lt;code&gt;run_backtest_dynamic()&lt;/code&gt; to allow returning how many stocks to buy, as well as a &lt;code&gt;run_backtest_fixed()&lt;/code&gt; to still allow for a custom amount of money per trade.&lt;/p&gt;




&lt;h2&gt;
  
  
  What’s Next
&lt;/h2&gt;

&lt;p&gt;I’ve considered adding features like running multiple strategies simultaneously and more advanced metrics. One comment reminded me of risk-adjusted performance measures — without metrics like Sharpe ratio or drawdowns, Stocksimpy is just a toy. Implementing these will be the focus of the next post.&lt;/p&gt;

&lt;p&gt;Visualization and documentation cleanup are still on the roadmap, but risk-adjusted calculations take priority. Stay tuned.&lt;/p&gt;




&lt;p&gt;Please check out Stocksimpy Github and give any feedback that you see appropriate. I hope this project helps out instead of wrestling with complex libraries. See you in the next post 👋:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/SuleymanSade/StockSimPy?source=post_page-----4a54a29c27b0---------------------------------------" rel="noopener noreferrer"&gt;GitHub - SuleymanSade/StockSimPy: A lightweight Python library for backtesting stock strategies&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Also check out my socials and let's connect:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🧠 Follow me on &lt;a href="https://x.com/SuleymanSade09" rel="noopener noreferrer"&gt;Twitter / X&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🔷 I’m now on &lt;a href="https://bsky.app/profile/suleymansade.bsky.social" rel="noopener noreferrer"&gt;Bluesky&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📰 Or read more of my posts on &lt;a href="https://medium.com/@suleymansade09" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;💬 Let’s connect on &lt;a href="https://www.linkedin.com/in/suleymansade/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>programming</category>
      <category>beginners</category>
      <category>opensource</category>
      <category>learning</category>
    </item>
    <item>
      <title>Inside the Portfolio: How Stocksimpy Tracks Trades and Value</title>
      <dc:creator>Suleyman Sade</dc:creator>
      <pubDate>Wed, 03 Sep 2025 00:35:58 +0000</pubDate>
      <link>https://dev.to/suleyman_sade/inside-the-portfolio-how-stocksimpy-tracks-trades-and-value-15b0</link>
      <guid>https://dev.to/suleyman_sade/inside-the-portfolio-how-stocksimpy-tracks-trades-and-value-15b0</guid>
      <description>&lt;h4&gt;
  
  
  From Cash to Stocks: Watch Your Portfolio in Action
&lt;/h4&gt;

&lt;p&gt;This is part 5 of my “Building Stocksimpy” series, where I’m building a lightweight Python stock backtesting library from zero.&lt;/p&gt;

&lt;p&gt;In the last post, I explained why I want Stocksimpy to stay simple: each class should have a clear purpose, instead of dumping everything in one giant backtester class.&lt;/p&gt;

&lt;p&gt;This was why I had created &lt;code&gt;StockData&lt;/code&gt; earlier to manage the stock price history. But only knowing the prices of stocks doesn’t get you far — I needed a way to track available cash, trades, and holdings. That’s where the &lt;code&gt;Portfolio&lt;/code&gt; comes in.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why a Portfolio Class?
&lt;/h3&gt;

&lt;p&gt;Indicators are useless without an account keeping track of your trades — so I built the &lt;code&gt;Portfolio&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Portfolio&lt;/code&gt; is essentially the &lt;strong&gt;accountant&lt;/strong&gt;, keeping track of all the money flow. Sure, you could track this with a data frame inside the backtesting loop. So why use &lt;code&gt;Portfolio&lt;/code&gt;? There is a principle in software development called:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Don’t Repeat Yourself (DRY)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Coding consists of objects, functions, classes, and many more. Why repeat yourself again and again when you could just call the same function? This is the main reason why I wanted a centralized &lt;code&gt;Portfolio&lt;/code&gt; class.&lt;/p&gt;

&lt;p&gt;And not only that, having a &lt;code&gt;Portfolio&lt;/code&gt; class allowed me to separate cash flow and actually run the backtesting logic, so instead of trying to push everything together, I could separate different tasks in the code. Otherwise, I would be rewriting buy/sell logic over and over again, and imagine having to change a minor error in that code — I am leaving the rest to your imagination.&lt;/p&gt;

&lt;h3&gt;
  
  
  Three Core Responsibilities
&lt;/h3&gt;

&lt;p&gt;What comes to your mind when I say Portfolio — in trading: total money, stocks, and other equities. That is exactly what &lt;code&gt;Portfolio&lt;/code&gt; does, additionally, anything that is related to the flow and recording of that money/holdings. &lt;/p&gt;

&lt;h4&gt;
  
  
  Storing cash and holdings
&lt;/h4&gt;

&lt;p&gt;At its core, Portfolio keeps track of your available cash (&lt;code&gt;self.cash&lt;/code&gt;) and all your holdings (&lt;code&gt;self.holdings&lt;/code&gt;). This may sound simple, but having a single place for this information prevents mistakes and makes the code cleaner.&lt;/p&gt;

&lt;h4&gt;
  
  
  Buy and sell operations
&lt;/h4&gt;

&lt;p&gt;I didn’t want the backtester loop to have direct access to the cash and holdings. So I decided the second responsibility should be buy/sell operations. Now buying/selling would require &lt;code&gt;Portfolio&lt;/code&gt; knowing the current price of the stock, meaning it needs &lt;code&gt;StockData&lt;/code&gt; which was something I was against doing, as &lt;code&gt;Portfolio&lt;/code&gt; had to be used standalone. &lt;/p&gt;

&lt;p&gt;Solution? I just added &lt;code&gt;price&lt;/code&gt; parameter to &lt;code&gt;exec_trade()&lt;/code&gt; so that this value could be provided by the backtesting loop or the user directly. And the direct access and alteration are done by &lt;code&gt;exec_trade()&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Tracking history
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;Porfolio&lt;/code&gt; may seem complete by now, but there is a 3rd critical responsibility: tracking history. User needs to be able to access the portfolio changes when the simulation buys/sells stock, and the total valuation. This was fairly easy to implement by &lt;code&gt;_log_trade()&lt;/code&gt; recording every trade in &lt;code&gt;self.trade_log&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here is an example run of how it works:&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="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;portfolio&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Portfolio&lt;/span&gt;

&lt;span class="c1"&gt;# Start out with $10,000
&lt;/span&gt;&lt;span class="n"&gt;myportfolio&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Portfolio&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;initial_cap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10_000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Buy 10 NVDA stocks at $170 per stock
&lt;/span&gt;&lt;span class="n"&gt;myportfolio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exec_trade&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;NVDA&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;trade_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;Buy&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;170&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;shares&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;current_date&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An interesting bug I encountered: Python won’t let you increment a value for a key that doesn’t exist yet in a dictionary. The solution? Use &lt;code&gt;defaultdict(int)&lt;/code&gt; from Python’s &lt;code&gt;collections&lt;/code&gt; module. This automatically initializes new keys to 0, solving the problem neatly.&lt;/p&gt;

&lt;h4&gt;
  
  
  Future?
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;Portfolio&lt;/code&gt; is designed to act &lt;strong&gt;independently,&lt;/strong&gt; so it can be used in custom backtesting loops. It already handles multiple stocks without issue, although the first version of Backtester won’t fully leverage them yet. &lt;/p&gt;

&lt;p&gt;Next up: Backtesting logic.&lt;/p&gt;

&lt;h4&gt;
  
  
  What else?
&lt;/h4&gt;

&lt;p&gt;If there are any suggestions or improvements you want for &lt;code&gt;Stocksimpy.&lt;/code&gt; Please let me know through either my socials or by directly commenting on them. I want this library to be useful to others, and anyone who is just starting out with quant finance.&lt;/p&gt;




&lt;p&gt;Thanks for reading — hope you enjoyed. Before you leave, please:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;⭐ Star stocksimpy on &lt;a href="https://medium.com/r/?url=https%3A%2F%2Fgithub.com%2FSuleymanSade%2FStockSimPy" rel="noopener noreferrer"&gt;Github&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🧠 Follow me on &lt;a href="https://medium.com/r/?url=https%3A%2F%2Fx.com%2FSuleymanSade09" rel="noopener noreferrer"&gt;Twitter / X&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🔷 I’m now on &lt;a href="https://medium.com/r/?url=https%3A%2F%2Fbsky.app%2Fprofile%2Fsuleymansade.bsky.social" rel="noopener noreferrer"&gt;Bluesky&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📰 Or read more of my posts on &lt;a href="https://medium.com/@suleymansade09" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;💬 Let’s connect on &lt;a href="https://medium.com/r/?url=https%3A%2F%2Fwww.linkedin.com%2Fin%2Fsuleymansade%2F" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>programming</category>
      <category>python</category>
      <category>opensource</category>
      <category>learning</category>
    </item>
    <item>
      <title>A change in vision | Building Stocksimpy (Devlog 4)</title>
      <dc:creator>Suleyman Sade</dc:creator>
      <pubDate>Wed, 27 Aug 2025 19:19:52 +0000</pubDate>
      <link>https://dev.to/suleyman_sade/a-change-in-vision-building-stocksimpy-devlog-4-hb5</link>
      <guid>https://dev.to/suleyman_sade/a-change-in-vision-building-stocksimpy-devlog-4-hb5</guid>
      <description>&lt;h4&gt;
  
  
  Imagine being able to test your strategy in less than 10 lines of Python code, rather than spending hours with other libraries. This is what will make &lt;code&gt;Stocksimpy&lt;/code&gt; useful.
&lt;/h4&gt;

&lt;p&gt;This is the 4th (technically 5th) post in my devlog series on building &lt;code&gt;Stocksimpy&lt;/code&gt;, a lightweight Python backtesting library. Read the rest of the series &lt;a href="https://medium.com/@suleymansade09/list/building-stocksimpy-944f16d39f68" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I’ve been developing &lt;code&gt;Stocksimpy&lt;/code&gt; for about a month now. Along the way, I learned a lot, from how to properly document a library to how to write reusable code. Those were my original goals: I wanted to learn. But if I’m honest, learning for myself isn’t enough — I want to build something actually useful for others too.  &lt;/p&gt;

&lt;p&gt;This shift made me revisit the origin of &lt;code&gt;Stocksimpy&lt;/code&gt;.  &lt;/p&gt;

&lt;p&gt;The idea came when I was building a simple stock prediction script. I could generate numbers and plots, but all I saw was just a bunch of data flowing and no real sense of whether the model was “working.” Was it actually successful, or just noise?  &lt;/p&gt;

&lt;p&gt;Naturally, I looked for existing Python backtesting tools. What I found was overwhelming: libraries that required setting up accounts, managing APIs, and losing myself among lines of configuration. These are powerful tools, but for quick experimentation, they felt like overkill. I didn’t want complexity — I wanted something lightweight, intuitive, and well-documented.  &lt;/p&gt;

&lt;p&gt;That’s how the idea &lt;code&gt;Stocksimpy&lt;/code&gt; was born. A Python library designed to be simple enough for a weekend experiment, yet structured enough to scale as strategies get more advanced. From the start, I chose to build in public, updating the &lt;a href="https://github.com/SuleymanSade/StockSimPy" rel="noopener noreferrer"&gt;GitHub repo&lt;/a&gt; as the project grew.  &lt;/p&gt;

&lt;p&gt;But recently, I realised I was just re-implementing the same indicator logic that major libraries like &lt;code&gt;TA-Lib&lt;/code&gt; already provide. That was never the purpose of &lt;code&gt;Stocksimpy&lt;/code&gt;. So I am doing some reconfiguration on the skeleton of the library. Here is what it will look like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;indicators.py&lt;/strong&gt;: Contains some simple common indicators for quick testing and development.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;StockData&lt;/strong&gt;: Holds the &lt;code&gt;Pandas&lt;/code&gt; data frame related to stock data.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Portfolio&lt;/strong&gt;: Contains the history of buy/sell, currently held stocks, and manages buy/sell operations.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backtester&lt;/strong&gt;: Where the user inputs their strategy and a &lt;code&gt;StockData&lt;/code&gt; to test, where the main loop occurs.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Visualize&lt;/strong&gt;: Visualizes the result and change of the total amount.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I finished coding a working draft for the first three, and will post a blog post about &lt;code&gt;Portfolio&lt;/code&gt; soon.  &lt;/p&gt;

&lt;p&gt;As these are the main classes of my library, I am aiming for a workflow similar to the following:&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;strategy&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
  &lt;span class="c1"&gt;# This is where the user builds their own strategy
&lt;/span&gt;  &lt;span class="n"&gt;skip&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;stocksimpy&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;StockData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Visualize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Backtester&lt;/span&gt; &lt;span class="c1"&gt;# 1
&lt;/span&gt;
&lt;span class="c1"&gt;# Import the data, supports SQLite, pd.dataframe, dict, yfinance, and more
&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;StockData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# 2
&lt;/span&gt;
&lt;span class="c1"&gt;# Create a Backtester object with $100,000 initial money
&lt;/span&gt;&lt;span class="n"&gt;backtest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Backtester&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;strategy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;initial_cap&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;100000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# 3
&lt;/span&gt;
&lt;span class="c1"&gt;# Runs it
&lt;/span&gt;&lt;span class="n"&gt;backtest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run_backtest&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;# 4
&lt;/span&gt;
&lt;span class="c1"&gt;# Visualizes the cap change
&lt;/span&gt;&lt;span class="n"&gt;Visualize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;visualize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;backtest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# 5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So if this works as I expected, with only 5 lines of code it is possible to run a backtest for a strategy.  &lt;/p&gt;

&lt;p&gt;If there is anything you want me to add, or any suggestions, please reach out to me on my socials, or comment it below 👇. It really helps with improving the library.  &lt;/p&gt;




&lt;p&gt;If you would like to support me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;⭐ Star stocksimpy on &lt;a href="https://github.com/SuleymanSade/StockSimPy" rel="noopener noreferrer"&gt;Github&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🧠 Follow me on &lt;a href="https://x.com/SuleymanSade09" rel="noopener noreferrer"&gt;Twitter / X&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🔷 I’m now on &lt;a href="https://bsky.app/profile/suleymansade.bsky.social" rel="noopener noreferrer"&gt;Bluesky&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📰 Or read more of my posts on &lt;a href="https://medium.com/@suleymansade09" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;💬 Let’s connect on &lt;a href="https://www.linkedin.com/in/suleymansade/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks for reading — let me know what else you want me to add.  &lt;/p&gt;

</description>
      <category>programming</category>
      <category>python</category>
      <category>opensource</category>
      <category>learning</category>
    </item>
    <item>
      <title>Creating Stock Data | building stocksimpy 3</title>
      <dc:creator>Suleyman Sade</dc:creator>
      <pubDate>Wed, 20 Aug 2025 17:55:25 +0000</pubDate>
      <link>https://dev.to/suleyman_sade/creating-stock-data-building-stocksimpy-3-28dg</link>
      <guid>https://dev.to/suleyman_sade/creating-stock-data-building-stocksimpy-3-28dg</guid>
      <description>&lt;p&gt;StockSimPy is a lightweight Python library for simple stock backtesting. The goal is to understand Pandas, experiment with stock strategies better, and create an easy-to-use alternative to more complex backtesting tools. This is part 3 of the series where I build this library in public.&lt;/p&gt;

&lt;p&gt;After finishing basic indicator calculation functions, I needed a way to keep track of all the stock information in an organised, reusable format. That’s where the &lt;code&gt;StockData&lt;/code&gt; comes in — it acts as a container for everything you’ll need in backtesting or simulation.&lt;/p&gt;

&lt;p&gt;I initially thought it should be easy to code as it just needed to keep the information and require some simple import and export, but I was quite wrong. Turns out working with data can be messy.&lt;/p&gt;

&lt;h3&gt;
  
  
  Data Validation
&lt;/h3&gt;

&lt;p&gt;When importing stock data, you can’t assume the columns are always consistent. Strategies require the use of different features, but some fields are essential:&lt;/p&gt;

&lt;p&gt;The tricky path — though — is naming conventions. What do I mean? &lt;/p&gt;

&lt;p&gt;Let's take “Open” as an example; it could show up as “OPEN”, “open”, “OpeN”, “open_price”, “OpenPrice”, “openPrice”, and many other wild naming styles.&lt;/p&gt;

&lt;p&gt;Lowercasing handles some cases, but what about the ones with “price” in the name? Then I thought — I could easily search for the substring “open” in the whole word. This covers all the cases I mentioned above, but if open is named something else entirely, it wouldn’t work.&lt;/p&gt;

&lt;p&gt;A more comprehensive approach might be to create a full-blown synonym-matching system. But that might be overkill for now. Still, I might add it as a feature in the future if somebody requests it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Data Import
&lt;/h3&gt;

&lt;p&gt;The most important feature of &lt;code&gt;StockData&lt;/code&gt; is importing data—without that, it’s just an empty shell.&lt;/p&gt;

&lt;p&gt;I was quite skeptical about creating these import functions at first. I considered leaving import up to the user — just pass in a Pandas DataFrame — but having built-in loaders felt more convenient. So far, &lt;code&gt;StockData&lt;/code&gt; supports imports from:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SQLite&lt;/li&gt;
&lt;li&gt;CSV&lt;/li&gt;
&lt;li&gt;Excel&lt;/li&gt;
&lt;li&gt;Pandas DataFrame&lt;/li&gt;
&lt;li&gt;Python dictionary&lt;/li&gt;
&lt;li&gt;JSON&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(This process felt quite &lt;strong&gt;repetitive&lt;/strong&gt; as I was just using built-in pandas functions or just straight-up copying documentation.)&lt;/p&gt;

&lt;p&gt;To simplify things, I added an&lt;code&gt;auto_loader()&lt;/code&gt; function that picks the correct import based on the file extension of &lt;code&gt;source&lt;/code&gt; parameter. I used &lt;code&gt;**kwargs&lt;/code&gt; so users can pass in additional parameters.&lt;/p&gt;

&lt;p&gt;On top of that, &lt;code&gt;StockData&lt;/code&gt; integrates directly with &lt;strong&gt;yfinance&lt;/strong&gt; (optional dependency). This allows fetching live stock data for a given ticker and date range, making it much more practical.&lt;/p&gt;

&lt;p&gt;For testing purposes, there’s also a &lt;code&gt;generate_mock_data()&lt;/code&gt; function. It isn’t designed for real backtesting but is useful for experimenting with new features.&lt;/p&gt;

&lt;h3&gt;
  
  
  Data Export
&lt;/h3&gt;

&lt;p&gt;Here is a question: why export data you already imported? Two reasons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Users might want to inspect or clean their data after transformations.&lt;/li&gt;
&lt;li&gt; I will soon integrate the indicator functions from earlier posts, with &lt;code&gt;StockData&lt;/code&gt; so exporting results will be handy.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Export currently supports all the same formats mentioned in import, plus SQL. There is also a flexible &lt;code&gt;to_custom()&lt;/code&gt; function that lets you define your own export method.&lt;/p&gt;




&lt;p&gt;It was such a twist, this step turned out to be more about data flexibility rather than really "storing data." With StockData in place, stocksimpy now has a solid foundation for testing.&lt;/p&gt;

&lt;p&gt;If you want to use this library in the future, or have any ideas that I could add, go for it. Ask me in comments, connect with me on socials. I want to make this project something useful.&lt;/p&gt;




&lt;p&gt;Follow the rest of the series, watch me build in public.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🌟Star this on &lt;a href="https://github.com/SuleymanSade/StockSimPy" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🧠 Follow me on &lt;a href="https://x.com/SuleymanSade09" rel="noopener noreferrer"&gt;Twitter / X&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🔷 I’m now on &lt;a href="https://bsky.app/profile/suleymansade.bsky.social" rel="noopener noreferrer"&gt;Bluesky&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📰 Or read more of my posts here on &lt;a href="https://medium.com/@suleymansade09" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;💬 Let’s connect on &lt;a href="https://www.linkedin.com/in/suleymansade/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks for reading.&lt;/p&gt;

</description>
      <category>buildinpublic</category>
      <category>programming</category>
      <category>beginners</category>
      <category>python</category>
    </item>
    <item>
      <title>What Losing a Hackathon Taught Me About Code — and Myself</title>
      <dc:creator>Suleyman Sade</dc:creator>
      <pubDate>Wed, 13 Aug 2025 08:54:56 +0000</pubDate>
      <link>https://dev.to/suleyman_sade/what-losing-a-hackathon-taught-me-about-code-and-myself-2d8j</link>
      <guid>https://dev.to/suleyman_sade/what-losing-a-hackathon-taught-me-about-code-and-myself-2d8j</guid>
      <description>&lt;h2&gt;
  
  
  A self-reflection on my past project — DiaGuide — and what I learned about “good code”
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpkaglhib8ogmmm5gg8ve.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpkaglhib8ogmmm5gg8ve.png" alt=" " width="640" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I thought I had something good. &lt;em&gt;DiaGuide&lt;/em&gt; — a diabetes risk prediction app I built in under 48 hours — was working. The ML model ran fast, the precision was acceptable, and the website was clean. I even added subtitles to the demo, just to cover the “accessibility” criteria.&lt;/p&gt;

&lt;p&gt;I submitted it thinking, &lt;em&gt;This could win.&lt;/em&gt; I imagined the approval from the judges, getting that DevPost badge, and seeing a certificate with my name on it. Every notification made me reach for my phone.&lt;/p&gt;

&lt;p&gt;Then the winners were announced. I wasn’t on the list. I checked again, and there was nothing.&lt;/p&gt;

&lt;p&gt;That loss hurt more than I expected. This was supposed to be a simple project that I built over the weekend for fun. Then I looked back at my project, and I was confronted by some hard truths about design, collaboration, and what “good code” actually means.&lt;/p&gt;




&lt;h2&gt;
  
  
  Design
&lt;/h2&gt;

&lt;p&gt;The moment I opened the web page, I was greeted by a generic form design with nothing unique to offer — just a simple toggle select. Since I didn’t have much prior experience with UX/UI design or building interfaces, I used &lt;code&gt;Streamlit&lt;/code&gt; because it integrated well with the rest of my Python ML code. However, compared to the winners’ web pages — visually polished and built with React — mine felt way too simple.&lt;/p&gt;

&lt;p&gt;I knew this would be an issue before I even started coding, so I tried to make things more interesting by showing the form questions one at a time. But it didn’t work as I expected. There was a bug where, after I clicked “next,” the next question popped up beneath the previous one, and the old question wouldn’t disappear until I selected an answer for the new one. I decided to turn this bug into a feature, because it seemed nice at the time. But that was a mistake.&lt;/p&gt;

&lt;p&gt;Instead of making my form page feel more unique, it just made it look buggy. In some cases, the previous question would suddenly disappear in a jarring way; in others, the new question would collapse to the top, forcing the user to move the cursor all the way up to continue.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Here is how annoying it is: — Screen recorded by author)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0oye7badndj7m5w6y2b3.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0oye7badndj7m5w6y2b3.gif" alt="A screen record of DiaGuide Webpage" width="800" height="503"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Collaboration
&lt;/h2&gt;

&lt;p&gt;Here’s a harsh truth I learned about building: one person cannot do everything perfectly. I soloed the whole project and did everything from front-end to ML models; I didn’t have time to perfect either, so the result felt rather incomplete.&lt;/p&gt;

&lt;p&gt;I learned that it is important to build in teams where everyone specializes in a certain aspect of code — one person builds the ML model, another the front-end, another the back-end, etc. That way, it’s much easier to build, and the result feels complete and functional.&lt;/p&gt;

&lt;p&gt;When I was building solo, I spent half my time switching hats — ML engineer, front-end developer, bug fixer, sysadmin. Every time I focused on one aspect, I had to completely switch gears and adapt for the other. This mental gear-shifting slowed me down significantly.&lt;/p&gt;

&lt;p&gt;But this doesn’t happen in a team; one person can work on polishing the UI while the other fine-tunes the ML model. The pieces come together faster, and you’re not stuck in “fix everything yourself” mode. It’s less stressful, and the result feels polished.&lt;/p&gt;

&lt;p&gt;Another important aspect of being in a team is continuous feedback. I believe one of the main reasons my project fell short is because I didn’t get feedback about how terrible my UI was. I’ll admit, it was unbearable. And I can definitely see that now. But when I was building it, it seemed perfectly fine and somewhat “original.”&lt;/p&gt;

&lt;p&gt;The excitement of building something and the stress of trying to finish on time made me blind to my project’s weaknesses. That’s why I wish I had worked with someone else. (I actually invited somebody, but they had something come up at the last minute.)&lt;/p&gt;

&lt;p&gt;I’ve talked all about the benefits of being in a team, but is being a solo builder that terrible? If you don’t like constantly giving updates, trying to glue every piece together, or spending hours convincing teammates to add certain features, then being solo might not be so bad.&lt;/p&gt;

&lt;p&gt;Being a solo developer can speed up some parts of the development since you don’t lose time communicating or trying to piece everything together.&lt;/p&gt;

&lt;p&gt;But I believe the time saved by being in a team is much more significant than the time saved by building solo.&lt;/p&gt;




&lt;h2&gt;
  
  
  What “Good Code” Really Means
&lt;/h2&gt;

&lt;p&gt;After losing, I went back through my code and realized it was full of little details that I loved but the user would never see. I spent quite a bit of time making all the questions line up perfectly with one another, but that didn’t benefit the user at all.&lt;/p&gt;

&lt;p&gt;I remember endlessly pressing Tab and arrow keys to fix indentation issues. But none of that was necessary.&lt;/p&gt;

&lt;p&gt;I’ve always loved coding with great structure — everything lined up perfectly, every variable name making sense. While that’s nice for developers, including myself, it doesn’t add anything for the user.&lt;/p&gt;

&lt;p&gt;The user doesn’t see my elegantly aligned lists or the clever Python trick I slipped in. They only care about what’s in front of them — because that’s actually what matters.&lt;/p&gt;

&lt;p&gt;When I think about what “good code” means, I ask myself: &lt;strong&gt;Why do we code? What’s the purpose?&lt;/strong&gt; It’s to build a product, maybe a service — not just to produce clean, well-organized code. Good code isn’t the end goal. It’s a tool to deliver something people find valuable.&lt;/p&gt;

&lt;p&gt;It doesn’t make sense to complicate your code when it has minimal effect on the user’s end. I spent a significant amount of time trying to make my form viewer “original” while I could have spent all that time trying to fix the buggy transition between questions.&lt;/p&gt;

&lt;p&gt;Looking back, that was the biggest shift in my mindset; good code isn’t about making the developer happy, it is about making the user’s life easier. I could use all the — so called — best tools in the world but if it doesn’t make a difference for the user, they are a waste of time.&lt;/p&gt;

&lt;p&gt;The realization stung because it meant I spent my 48 hours worrying about the wrong things instead of what really matters. But it also stuck with me — and weeks later, &lt;em&gt;DiaGuide&lt;/em&gt; still mattered to someone.&lt;/p&gt;

&lt;p&gt;One day I got a message on my Dev.to post explaining DiaGuide. It was from someone with type 2 diabetes. They wrote that tools like &lt;em&gt;DiaGuide&lt;/em&gt; can help people catch risk early and take action — and that it could encourage someone to take action.&lt;/p&gt;

&lt;p&gt;It wasn’t a certificate or a DevPost badge, but it felt better. I might have lost the hackathon, but I had built something that actually mattered to someone. And that’s the real reason it’s worth putting time and effort into building tools, websites, and anything else — because they can make a difference.&lt;/p&gt;




&lt;p&gt;I write about learning AI by &lt;strong&gt;building real tools&lt;/strong&gt;, not just tutorials.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;⭐ Star this on &lt;a href="https://github.com/SuleymanSade/DiaGuide" rel="noopener noreferrer"&gt;Github&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🧠 Follow me on &lt;a href="https://x.com/SuleymanSade09" rel="noopener noreferrer"&gt;Twitter / X&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🔷 I’m now on &lt;a href="https://bsky.app/profile/suleymansade.bsky.social" rel="noopener noreferrer"&gt;Bluesky&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📰 Or read more of my posts on &lt;a href="https://medium.com/@suleymansade09" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;💬 Let’s connect on &lt;a href="https://www.linkedin.com/in/suleymansade/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks for reading — let me know about your experiences with hackathons!&lt;/p&gt;

</description>
      <category>programming</category>
      <category>beginners</category>
      <category>devops</category>
      <category>learning</category>
    </item>
    <item>
      <title>🐍 Top Python Libraries to Supercharge Your Productivity</title>
      <dc:creator>Suleyman Sade</dc:creator>
      <pubDate>Sat, 02 Aug 2025 08:41:50 +0000</pubDate>
      <link>https://dev.to/suleyman_sade/top-python-libraries-to-supercharge-your-productivity-425i</link>
      <guid>https://dev.to/suleyman_sade/top-python-libraries-to-supercharge-your-productivity-425i</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvvvubo2kg3hlo4e8fkuv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvvvubo2kg3hlo4e8fkuv.png" alt="Cover Image: a snake moving around gears, files, and a box filled with these" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this blog post, I will cover some of the best libraries to manage documentation, dependencies, testing, formatting, and much more.&lt;/p&gt;

&lt;p&gt;As Python developers, we juggle a variety of tools — from testing frameworks to formatters, documentation tools to dependency managers — all in the name of productivity. But not all tools are created equal.&lt;/p&gt;

&lt;p&gt;In this post, I’ll walk you through some of the most effective Python libraries to help you write cleaner code, avoid technical debt, and speed up your development workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing Tools/Libraries
&lt;/h2&gt;

&lt;p&gt;Testing might feel like a roadblock when you just want to ship, but it’s essential for building maintainable, bug‑resistant code. These tools make testing faster and more intuitive:&lt;/p&gt;

&lt;h3&gt;
  
  
  1) Pytest:
&lt;/h3&gt;

&lt;p&gt;Pytest is the de facto standard for testing in Python — easy to start with, yet powerful enough for advanced use cases. It lets you assert function outputs, check for exceptions, and even parametrize tests for broader coverage.&lt;/p&gt;

&lt;p&gt;Basic assertion:&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;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&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;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_add&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Testing for exceptions:&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="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pytest&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;divide&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&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;y&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Cannot divide by zero&lt;/span&gt;&lt;span class="sh"&gt;"&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;x&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_divide&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
  &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;pytest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;raises&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;divide&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pytest also supports:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Parametrized testing with &lt;code&gt;@pytest.mark.parametrize&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Fixtures for reusable setup&lt;/li&gt;
&lt;li&gt;Plugins for test coverage, mocking, and more&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Documentation
&lt;/h2&gt;

&lt;p&gt;Documentation may feel like a distraction from “real coding,” but it is essential if you want your project to be usable, maintainable, or collaborative. Good documentation is the cornerstone for open‑source projects as it allows for other devs to easily understand why, how, and what you wrote in your code.&lt;/p&gt;

&lt;p&gt;Documentation not only helps others but also helps you by acting like a second brain when revisiting old code or reminding you why you made certain choices in your code.&lt;/p&gt;

&lt;p&gt;Here are two widely used Python tools for building documentation:&lt;/p&gt;

&lt;h3&gt;
  
  
  Sphinx
&lt;/h3&gt;

&lt;p&gt;Sphinx is a powerful tool originally built for Python’s own documentation. It uses reStructuredText (or Markdown with extensions) and supports automatic generation of API docs from your code’s docstrings. This means you don’t have to worry about updating your documentation when you change a docstring in your code. It automatically updates when you build, so it cuts the worry of switching between editing code and documentation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why use it:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Supports themes like Read the Docs
&lt;/li&gt;
&lt;li&gt;Integrates with Autodoc to generate docs from code
&lt;/li&gt;
&lt;li&gt;Great for large projects or libraries
&lt;/li&gt;
&lt;li&gt;Automates more of your workflow&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want to get started you can read the my following blog post: &lt;a href="https://medium.com/python-in-plain-english/setting-up-proper-documentation-with-sphinx-docs-building-stocksimpy-1-3cf28eff0168" rel="noopener noreferrer"&gt;Setting Proper Documentation With Sphinx Docs&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  MKDocs
&lt;/h3&gt;

&lt;p&gt;MKDocs is a simpler alternative using a Markdown-based static site generator designed for project documentation. It’s easier to configure than &lt;code&gt;Sphinx&lt;/code&gt; and has great theming support.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why use it:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Easy to write in Markdown
&lt;/li&gt;
&lt;li&gt;Fast to set up and deploy
&lt;/li&gt;
&lt;li&gt;Ideal for smaller projects, developer tools, or internal docs.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  MKDocs vs. Sphinx: Which Should You Use?
&lt;/h4&gt;

&lt;p&gt;Use Sphinx if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You are building a big project
&lt;/li&gt;
&lt;li&gt;Want to automate creating documentation
&lt;/li&gt;
&lt;li&gt;Okay with spending time configuring &lt;code&gt;Sphinx&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use MkDocs if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You want something quick, clean, and Markdown‑based
&lt;/li&gt;
&lt;li&gt;Building a small‑scale project
&lt;/li&gt;
&lt;li&gt;Don’t want to spend too much time on documentation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In short:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sphinx = More powerful, but more complex
&lt;/li&gt;
&lt;li&gt;MkDocs = Simpler, but less flexible for auto‑generating docs&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Code Formatting
&lt;/h2&gt;

&lt;p&gt;Code style shouldn’t be a matter of debate in a project; you don’t want to spend all your time formatting your code when you can build new features — that's why formatter tools are a necessary piece of your workflow.&lt;/p&gt;

&lt;p&gt;Formatter and linter tools help you enforce consistent style, catch bugs early, and reduce time wasted on code review nitpicks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Black
&lt;/h3&gt;

&lt;p&gt;Black is a code formatter that always formats your code to a consistent style — no configuration needed. This removes the need for making specific stylistic choices, potentially saving you both time and brain power.&lt;/p&gt;

&lt;p&gt;But there is a drawback: you can’t tweak the style — you either accept it or don’t use it. This could be a huge problem when you already have a codebase formatted differently from “Blackened” code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Usage:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;black main.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Ruff
&lt;/h3&gt;

&lt;p&gt;Ruff is a fast Python linter and formatter written in Rust. If you have a big codebase that requires blazing‑fast formatting, this is your option.&lt;/p&gt;

&lt;p&gt;Unlike Black, Ruff is highly configurable with compatibility for many common linter rule sets. It can replace multiple tools as it combines linting and formatting in one tool.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Usage:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ruff check project/
ruff format project/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Flake8
&lt;/h3&gt;

&lt;p&gt;Flake8 is a classic Python linter that checks for PEP8 compliance and potential bugs. It is widely adopted in the industry, with many plugins to make it suitable for your needs.&lt;/p&gt;

&lt;p&gt;It integrates well with other tools and IDEs; however, it is slower than Ruff and requires multiple plugins to match modern standards.&lt;/p&gt;

&lt;h4&gt;
  
  
  Which One Should You Use?
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Use Black if:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You want a simple, consistent formatter
&lt;/li&gt;
&lt;li&gt;Don’t want to spend much time worrying about style&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Use Ruff if:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You want an all‑in‑one linter/formatter
&lt;/li&gt;
&lt;li&gt;Require high customizability and speed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Use Flake8 if:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You're working in a legacy codebase or team dependent on it
&lt;/li&gt;
&lt;li&gt;Need integration with specific IDE tooling&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Type Checking
&lt;/h2&gt;

&lt;p&gt;Python is a dynamic programming language, meaning it doesn’t require you to choose certain types for your variables. This offers great flexibility but comes with a major caveat: errors.&lt;/p&gt;

&lt;p&gt;Static type checking helps catch bugs before runtime, improves IDE support, and clarifies intent, as well as making your code more readable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mypy
&lt;/h3&gt;

&lt;p&gt;Mypy is a static type checker that works with Python’s built-in &lt;code&gt;type hints&lt;/code&gt; to validate your code before execution.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Basic Example:&lt;/strong&gt;&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;greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello, &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;square&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&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;n&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, if you accidentally call &lt;code&gt;square("4")&lt;/code&gt;, Mypy will raise an error.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Usage:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mypy main.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Dependency Management
&lt;/h2&gt;

&lt;p&gt;We discussed several tools that you can already use, and as your project scales, the number of dependencies will scale tremendously. Managing all these dependencies is crucial for reproducibility and collaboration. Here are two tools to make this seemingly annoying process easier and more consistent than using plain &lt;code&gt;pip&lt;/code&gt; and &lt;code&gt;venv&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pipenv
&lt;/h3&gt;

&lt;p&gt;Pipenv combines &lt;code&gt;pip&lt;/code&gt; and &lt;code&gt;virtualenv&lt;/code&gt; into a unified workflow. It generates &lt;code&gt;Pipfile&lt;/code&gt; and &lt;code&gt;Pipfile.lock&lt;/code&gt; to keep track of your dependencies and manage your virtual environment.&lt;/p&gt;

&lt;p&gt;These tools simplify setting up your environment as well as your dependencies, and the lockfiles ensure reproducible builds, so clients don’t face unexpected issues. However, dependency resolution can be slow, and development activity has slowed recently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Usage:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pipenv install requests
pipenv shell
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Poetry
&lt;/h3&gt;

&lt;p&gt;Poetry is a more modern alternative to manage your venvs, dependencies, and Python packaging — all in one place.&lt;/p&gt;

&lt;p&gt;It uses the new &lt;code&gt;pyproject.toml&lt;/code&gt; standard, is faster, deterministic in dependency resolution, and easier to publish to PyPI. That said, it can be harder to set up and less beginner-friendly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Usage:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;poetry init
poetry add pandas
poetry shell
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Which One Should You Use?
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pipenv&lt;/strong&gt; if you're starting small or need something beginner-friendly
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Poetry&lt;/strong&gt; if you want performance, modern workflows, and are packaging or scaling your project&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Conclusion: Choose Tools That Scale With You
&lt;/h2&gt;

&lt;p&gt;Productivity in Python isn’t about piling on tools, chasing hype, or pouring hours into complex workflows when that time could go into code.&lt;/p&gt;

&lt;p&gt;It’s about choosing tools that align with your workflow, team, and project’s scale. Sometimes the smartest choice is &lt;em&gt;not&lt;/em&gt; adding another dependency.&lt;/p&gt;

&lt;p&gt;If you're just getting started, begin with &lt;strong&gt;Black&lt;/strong&gt;, &lt;strong&gt;Pytest&lt;/strong&gt;, and &lt;strong&gt;Pipenv&lt;/strong&gt;. You don’t need the most advanced tools right away.&lt;/p&gt;

&lt;p&gt;The ecosystem is rich—but you don’t need everything. Adopt tools incrementally.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The best tooling isn’t the most powerful — it’s the one that removes friction without getting in your way&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;I write about learning AI by building real tools, not just tutorials.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🧠 Follow me on &lt;a href="https://x.com/SuleymanSade09" rel="noopener noreferrer"&gt;Twitter / X&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🔷 I’m now on &lt;a href="https://bsky.app/profile/suleymansade.bsky.social" rel="noopener noreferrer"&gt;Bluesky&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📰 Or read more of my posts on &lt;a href="https://medium.com/@suleymansade09" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;💬 Let’s connect on &lt;a href="https://www.linkedin.com/in/suleymansade/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks for reading — let me know which one of these you would use/ have used.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>python</category>
      <category>softwaredevelopment</category>
      <category>development</category>
    </item>
    <item>
      <title>From SMA to TEMA: Coding Technical Indicators in Python — Building stocksimpy 2</title>
      <dc:creator>Suleyman Sade</dc:creator>
      <pubDate>Sat, 26 Jul 2025 06:44:31 +0000</pubDate>
      <link>https://dev.to/suleyman_sade/from-sma-to-tema-coding-technical-indicators-in-python-building-stocksimpy-2-3162</link>
      <guid>https://dev.to/suleyman_sade/from-sma-to-tema-coding-technical-indicators-in-python-building-stocksimpy-2-3162</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7sj8nxx9xaqga3z35cfq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7sj8nxx9xaqga3z35cfq.png" alt="Graph of different indicators" width="800" height="471"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Most of the stock back-testing tools and libraries I've seen are either too complex for beginners or have a steep learning curve. So I decided to build my own Python library from scratch called &lt;code&gt;stocksimpy&lt;/code&gt; which aims to be a light-weight and well-documented alternative to what is out there.&lt;/p&gt;

&lt;p&gt;One of my primary goals with this series is to learn how Python libraries work, as well as to improve my skills in &lt;code&gt;Pandas&lt;/code&gt; and &lt;code&gt;NumPy&lt;/code&gt;. And create something that could grow into a real tool for others to use.&lt;/p&gt;

&lt;p&gt;In the process, I ended up implementing over 10 indicators from scratch.&lt;/p&gt;

&lt;p&gt;Here’s how I approached, what I learned, and how you can do the same:&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Build Indicators From Scratch?
&lt;/h2&gt;

&lt;p&gt;This is a valid question. I also asked myself this when I reached about 300 lines of code. But then I realised that when I was coding these indicators, I was learning how they work. This hit me when suddenly the equation for TEMA calculation appeared in my eyes:&lt;/p&gt;

&lt;blockquote&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(3 * EMA_1) — (3*EMA_2) + EMA_3
&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;This was enough to prove that I was learning something, and I was also getting better at using &lt;code&gt;Pandas&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;This was also &lt;strong&gt;my&lt;/strong&gt; Python library that &lt;strong&gt;I&lt;/strong&gt; built from &lt;strong&gt;zero&lt;/strong&gt;, so I wanted to have &lt;strong&gt;total control&lt;/strong&gt; over what to include and how to organize them.&lt;/li&gt;
&lt;li&gt;Also, something about Python libraries is that you want to keep dependencies to a minimum, and I already had to use &lt;code&gt;NumPy&lt;/code&gt; and &lt;code&gt;Pandas&lt;/code&gt; , so adding another packed dependency might have been too much — which I tried to avoid.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Deep Dive Into Common Indicators
&lt;/h2&gt;

&lt;p&gt;Overview of indicators implemented so far:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Moving Averages:&lt;/strong&gt; SMA, EMA, DEMA, TEMA, HMA&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Momentum Indicators:&lt;/strong&gt; RSI, MACD, Wilder’s MACD, HMA-MACD, TEMA-MACD&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Smoothing:&lt;/strong&gt; Wilder’s Smoothing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now let's break down each one of them as well as their implementations:&lt;/p&gt;

&lt;h3&gt;
  
  
  Simple Moving Average (SMA)
&lt;/h3&gt;

&lt;p&gt;SMA is just the average of a fixed number of consecutive values in a series. Let’s break it down:&lt;/p&gt;

&lt;p&gt;data_series = [1, 3, 4, 6, 8]&lt;/p&gt;

&lt;p&gt;window = 3&lt;/p&gt;

&lt;p&gt;Now, calculate the average of each group of consecutive numbers:&lt;/p&gt;

&lt;p&gt;The first two numbers don’t have enough data before them to form a full window, so we assign &lt;code&gt;NaN&lt;/code&gt; for them.&lt;/p&gt;

&lt;p&gt;Next values are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;(1 + 3 + 4)/3 = 2.67&lt;/li&gt;
&lt;li&gt;(3 + 4 + 6)/3 = 4.33&lt;/li&gt;
&lt;li&gt;(4 + 6 + 8)/3 = 6.0&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the result should look like this:&lt;/p&gt;

&lt;p&gt;[Nan, Nan, 2.67, 4.33, 6.0]&lt;/p&gt;

&lt;p&gt;This could be implemented easily in Python:&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;calculate_sma&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data_series&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Series&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&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;data_series&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rolling&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;mean&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 code, we use &lt;code&gt;.rolling(window)&lt;/code&gt; to create a moving window of specified size, and get the average of each using &lt;code&gt;mean()&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Weighted Moving Average (WMA)
&lt;/h3&gt;

&lt;p&gt;While SMA gives equal weight to all the values in a given window, we sometimes want to give more weight to recent values to make it more responsive to recent price changes. This is when WMA is used:&lt;/p&gt;

&lt;p&gt;The formula is linear:&lt;/p&gt;

&lt;p&gt;WMA(n) = (V₀ × n + V₁ × (n−1) + V₂ × (n−2) + … + Vₙ₋₁ × 1) / (n + (n−1) + … + 1)&lt;/p&gt;

&lt;p&gt;Where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;V₀ is the most recent value&lt;/li&gt;
&lt;li&gt;n is the window size&lt;/li&gt;
&lt;li&gt;The denominator is the sum of the weights: n(n + 1)/2&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Exponential Moving Average (EMA):
&lt;/h3&gt;

&lt;p&gt;WMA helps with giving some weight, but sometimes you want to be even more responsive to recent changes. This is where we use EMA, which weights exponentially instead of linearly, and also forms the foundation for indicators like MACD.&lt;/p&gt;

&lt;p&gt;Calculating EMA is a bit more complicated than the previous two.&lt;/p&gt;

&lt;p&gt;To calculate the current EMA value, you need the EMA of the previous day, so it requires a recursive pattern. Here is the equation:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffdpk6i9b106xgxxjbr7y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffdpk6i9b106xgxxjbr7y.png" alt="equation for EMA" width="800" height="362"&gt;&lt;/a&gt;&lt;br&gt;
Source: &lt;a href="https://www.investopedia.com/ask/answers/122314/what-exponential-moving-average-ema-formula-and-how-ema-calculated.asp" rel="noopener noreferrer"&gt;How Is the Exponential Moving Average (EMA) Formula Calculated?&lt;br&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Even though the calculation seems complicated, the code implementation is pretty easy:&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;calculate_ema&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data_series&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Series&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Series&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;data_series&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ewm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;span&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;adjust&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;min_periods&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;.ewm()&lt;/code&gt; applies the exponential weighting and span=window ensures that it uses the k equation described above. &lt;code&gt;adjust=false&lt;/code&gt; makes sure that it uses recursion. And the final &lt;code&gt;.mean()&lt;/code&gt; calculates the EMA.&lt;/p&gt;

&lt;h3&gt;
  
  
  Double Exponential Moving Average (DEMA)
&lt;/h3&gt;

&lt;p&gt;DEMA is designed to reduce the lag that is found in EMA by combining two EMAs into one formula.&lt;/p&gt;

&lt;p&gt;Formula is as follows:&lt;/p&gt;

&lt;p&gt;DEMA = 2 × EMA1 — EMA2&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;EMA1: standard EMA&lt;/li&gt;
&lt;li&gt;EMA2: EMA of EMA1&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Meaning you first find the standard EMA and then find the EMA of EMA, and finish by combining these two EMAs into one.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Why does DEMA reduce lag?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In standard EMA or SMA, sudden changes in value take time to recover — since we are still using the previous values to get the EMA/SMA. For example, in [100, 101, 102, 120, 121, 122] there is a sudden increase from 102 to 120, but when calculating EMA, the first values that are close to 100s are going to bring the average down from 120 to 110ish, which is called lag.&lt;/p&gt;

&lt;p&gt;What DEMA does is that it calculates the EMA of EMA so that it lags even further and then subtracts it from the standard EMA times 2, essentially pulling the result forward.&lt;/p&gt;

&lt;p&gt;Here is a Python implementation of DEMA using the previous &lt;code&gt;calculate_ema()&lt;/code&gt; function:&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;calculate_dema&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data_series&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Series&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Series&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="n"&gt;ema1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;calculate_ema&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data_series&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;ema2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;calculate_ema&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ema1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="nf"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;ema1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;ema2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We calculate the &lt;code&gt;ema1&lt;/code&gt; by getting the EMA of &lt;code&gt;data_series&lt;/code&gt; and then &lt;code&gt;ema2&lt;/code&gt; by calculating the EMA of &lt;code&gt;ema1&lt;/code&gt;. Then we do the calculation and return it — pretty simple.&lt;/p&gt;

&lt;h3&gt;
  
  
  Triple Exponential Moving Average (TEMA):
&lt;/h3&gt;

&lt;p&gt;TEMA takes the concept behind DEMA one step further by combining 3 EMAs into one, smoother, and even more responsive indicator.&lt;/p&gt;

&lt;p&gt;The formula looks slightly complex, but it follows a similar idea:&lt;/p&gt;

&lt;p&gt;TEMA = (3 × EMA_1) — (3 × EMA_2) + EMA_3&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;EMA_1: Standard EMA&lt;/li&gt;
&lt;li&gt;EMA_2: EMA of EMA_1&lt;/li&gt;
&lt;li&gt;EMA_3: EMA of EMA_3&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, how does this help?&lt;/p&gt;

&lt;p&gt;Each layer adds more smoothness — but also more lag.&lt;/p&gt;

&lt;p&gt;TEMA corrects for this by amplifying the most recent EMA (3 × EMA_1), which results in 3×lag, subtracting out the additional lag (3 × EMA_2), which is 3xlag - 6xlag = -3lag. Then the final EMA_3 is used to avoid overcompensation: -3lag + 3lag = 0lag — which means no lag.&lt;/p&gt;

&lt;p&gt;Here is my Python implementation in &lt;code&gt;stocksimpy&lt;/code&gt; :&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;calculate_tema&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data_series&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Series&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Series&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  
  &lt;span class="n"&gt;ema1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;calculate_ema&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data_series&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;ema2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;calculate_ema&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ema1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;ema3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;calculate_ema&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ema2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="nf"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ema1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ema2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;ema3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I think the code is pretty straightforward. It uses &lt;code&gt;calculate_ema()&lt;/code&gt; to calculate &lt;code&gt;ema1&lt;/code&gt; , &lt;code&gt;ema2&lt;/code&gt; and &lt;code&gt;ema3&lt;/code&gt; . Then the equation is implemented.&lt;/p&gt;

&lt;h3&gt;
  
  
  What’s Next?
&lt;/h3&gt;

&lt;p&gt;These moving averages (MA) form the foundation of many powerful technical indicators used in trading and analysis. By building them from scratch, you not only gain a deeper understanding of how they work but also how to improve your skills with &lt;code&gt;Pandas&lt;/code&gt; and &lt;code&gt;NumPy&lt;/code&gt; .&lt;/p&gt;

&lt;p&gt;In the next article in this series, I’ll dive into momentum indicators like &lt;strong&gt;RSI,&lt;/strong&gt; &lt;strong&gt;MACD,&lt;/strong&gt; and some custom variations — showing you how to implement these step-by-step.&lt;/p&gt;




&lt;p&gt;I write about learning AI by &lt;strong&gt;building real tools&lt;/strong&gt;, not just tutorials.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🧠 Follow me on &lt;a href="https://x.com/SuleymanSade09" rel="noopener noreferrer"&gt;Twitter / X&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🔷 I’m now on &lt;a href="https://bsky.app/profile/suleymansade.bsky.social" rel="noopener noreferrer"&gt;Bluesky&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📰 Or read more of my posts here on &lt;a href="https://medium.com/@suleymansade09" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;💬 Let’s connect on &lt;a href="https://www.linkedin.com/in/suleymansade/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Here is the GitHub link to &lt;code&gt;stocksimpy&lt;/code&gt; which contains all the functions used in this article, and most of the equations:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/SuleymanSade/StockSimPy/tree/dev?source=post_page-----16e684091789---------------------------------------" rel="noopener noreferrer"&gt;https://github.com/SuleymanSade/StockSimPy/tree/dev?source=post_page-----16e684091789---------------------------------------&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>programming</category>
      <category>beginners</category>
      <category>learning</category>
    </item>
    <item>
      <title>Setting up proper documentation with Sphinx docs — Building stocksimpy 1</title>
      <dc:creator>Suleyman Sade</dc:creator>
      <pubDate>Fri, 18 Jul 2025 19:52:49 +0000</pubDate>
      <link>https://dev.to/suleyman_sade/setting-up-proper-documentation-with-sphinx-docs-building-stocksimpy-1-4gfg</link>
      <guid>https://dev.to/suleyman_sade/setting-up-proper-documentation-with-sphinx-docs-building-stocksimpy-1-4gfg</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmuhniqvawm62k1trv7hl.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmuhniqvawm62k1trv7hl.webp" alt="Cover image: A Python code screen is open next to a title " width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hi there! If you are new to this series, “Building stocksimpy” is a series where I create a new Python library from scratch, documenting every step along the way. The goal of the library is to be a lightweight, open-source, and well-documented alternative to other stock strategy testing libraries.&lt;/p&gt;

&lt;p&gt;It’s a journey for me to &lt;em&gt;learn Python, improve my software engineering skills, and explore data science.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Set Up Sphinx Docs Now?
&lt;/h2&gt;

&lt;p&gt;One of my main goals with stocksimpy is to keep the codebase &lt;em&gt;beginner-friendly and maintainable.&lt;/em&gt; That means having great documentation from day one.&lt;/p&gt;

&lt;p&gt;Instead of manually writing Markdown and trying to keep the documentation updated every time I make a small change, I decided to use Sphinx, a powerful tool to auto-generate HTML documentation for Python code’s docstrings.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Sphinx?
&lt;/h2&gt;

&lt;p&gt;Sphinx is a documentation generator that pulls information directly from your code, and Sphinx docs automatically detect all of your &lt;strong&gt;docstrings&lt;/strong&gt; in your &lt;code&gt;.py&lt;/code&gt; files. Then, it generates an HTML file containing all of your documentation in an organized manner. It is widely used in the Python ecosystem, including major libraries like &lt;code&gt;NumPy&lt;/code&gt;, &lt;code&gt;pandas&lt;/code&gt;, and &lt;code&gt;scikit-learn&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It might seem like a small help, but in reality, constantly updating your documentation as you build new functions or changing the documentation that you already wrote is hard to maintain. And making all this look good at the same time just becomes a headache. Sphinx does all this for you so you can focus on writing your code.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Set up Sphinx?
&lt;/h2&gt;

&lt;p&gt;First, locate the directory that contains your project. Then, to set up Sphinx docs, I would suggest creating a new folder called &lt;code&gt;docs&lt;/code&gt;. This helps keep everything organized.&lt;/p&gt;

&lt;p&gt;Locate the &lt;code&gt;docs&lt;/code&gt; directory, and then if you haven’t downloaded Sphinx before, run the following line(s):&lt;/p&gt;

&lt;h3&gt;
  
  
  Create Virtual Environment(recommended):
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="n"&gt;venv&lt;/span&gt; &lt;span class="n"&gt;venv&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Activate the virtual environment&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;On Windows:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;venv&lt;/span&gt;\&lt;span class="n"&gt;Scripts&lt;/span&gt;\&lt;span class="n"&gt;activate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bat&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;On Linux/macOS:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;source&lt;/span&gt; &lt;span class="n"&gt;venv&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nb"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;activate&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Install Sphinx
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;pip&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt; &lt;span class="n"&gt;spinx&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to, like I did, you can install a popular theme like &lt;code&gt;sphinx_rtd_theme&lt;/code&gt;:&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="n"&gt;pip&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt; &lt;span class="n"&gt;sphinx_rtd_theme&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Setting up Spinx
&lt;/h3&gt;

&lt;p&gt;To get started, you can run the following line:&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="n"&gt;sphinx&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;quickstart&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will ask you the following questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Separate source and build directories (y/n):&lt;/strong&gt; Generally, saying y is a good choice as it keeps your directory cleaner, which is also what I did.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Project name, author, version, release:&lt;/strong&gt; Fill these in as appropriate. If this is your first release, you could say &lt;code&gt;0.1.0&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;autodoc:&lt;/strong&gt; automatically insert docstrings from modules (y/n) [n]: If you’re documenting Python code and want to automatically pull in docstrings, choose &lt;code&gt;y&lt;/code&gt;. This is highly recommended for Python projects.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After answering these questions, Sphinx is going to create a set of files. After that, your docs directory looks something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0du7ww9e9rnrodburcl6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0du7ww9e9rnrodburcl6.png" width="283" height="342"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Configuring conf.py
&lt;/h3&gt;

&lt;p&gt;All the information you just answered is stored in conf.py, and you can edit it as you wish. Here are some things to check: &lt;code&gt;project&lt;/code&gt;, &lt;code&gt;copyright&lt;/code&gt;, &lt;code&gt;author&lt;/code&gt;, &lt;code&gt;version&lt;/code&gt;, &lt;code&gt;release&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;extensions&lt;/code&gt;: This list defines which Sphinx extensions are active. If you chose &lt;code&gt;autodoc&lt;/code&gt; during quickstart, it should be there. Here are some others you might want to add:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;sphinx.ext.autodoc&lt;/code&gt;: for Python docstring&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sphinx.ext.napolean&lt;/code&gt;: if you use Google or NumPy style docstrings, I will show you an example&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sphinx.ext.viewcode&lt;/code&gt;: adds links to source code&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sphinx.ext.intersphinx&lt;/code&gt;: to link to the documentation of other Sphinx projects
Here is an example &lt;code&gt;extensions&lt;/code&gt; that I used in stocksimpy:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3i94t8wwwxu8asj1pu0y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3i94t8wwwxu8asj1pu0y.png" width="611" height="164"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you also installed the &lt;code&gt;sphinx_rts_theme&lt;/code&gt; I mentioned for a more modern look:&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="n"&gt;html_theme&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sphinx_rtd_theme&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And finally, at the top of your &lt;code&gt;conf.py&lt;/code&gt; you should have the following code:&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="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;
&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;abspath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;LINK_TO_YOUR_CODE&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fill in &lt;code&gt;LINK_TO_YOUR_CODE&lt;/code&gt; wherever your code is located. (Mine is “../../src”)&lt;/p&gt;

&lt;h3&gt;
  
  
  Add Content
&lt;/h3&gt;

&lt;p&gt;You can write your documentation in reStructuredText(&lt;code&gt;.rst&lt;/code&gt;).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;index.rst&lt;/code&gt; is your main entry point. It contains &lt;code&gt;toctree&lt;/code&gt;(table of contents tree) directive to link to other documentation files. Here is an example from my code:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F729i4a251nqxxr0iw1xn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F729i4a251nqxxr0iw1xn.png" alt=" " width="450" height="158"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For these references you need to create new &lt;code&gt;.rst&lt;/code&gt; files and in my case, I create &lt;code&gt;api.rst&lt;/code&gt; file (in source). In your other reference &lt;code&gt;.rst&lt;/code&gt; files you can directly bind it to a module, and it documents it for you!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is my &lt;code&gt;api.rst&lt;/code&gt;:&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="n"&gt;API&lt;/span&gt; &lt;span class="n"&gt;Reference&lt;/span&gt;
&lt;span class="o"&gt;=============&lt;/span&gt;

&lt;span class="p"&gt;..&lt;/span&gt; &lt;span class="n"&gt;automodule&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt; &lt;span class="n"&gt;stocksimpy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data_handler&lt;/span&gt;
   &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;members&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

&lt;span class="p"&gt;..&lt;/span&gt; &lt;span class="n"&gt;automodule&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt; &lt;span class="n"&gt;stocksimpy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;indicators&lt;/span&gt;
   &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;members&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;data_handler&lt;/code&gt; and &lt;code&gt;indicators&lt;/code&gt; are the names of my modules inside of my packages (&lt;code&gt;stocksimpy&lt;/code&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  Build Your Documentation
&lt;/h3&gt;

&lt;p&gt;Now you just need to run the following command in &lt;code&gt;docs&lt;/code&gt; directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;make html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;On windows:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;.&lt;span class="se"&gt;\m&lt;/span&gt;ake.bat html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then it should create your documentation in &lt;code&gt;_build\html&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;And that’s it, you now have documentation for your code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Next Steps
&lt;/h3&gt;

&lt;p&gt;After setting up Sphinx, you can use &lt;a href="https://about.readthedocs.com/" rel="noopener noreferrer"&gt;Read the Docs&lt;/a&gt; to publish your documentation online. If your project is open-source, you can share your documentation with everyone for &lt;em&gt;free&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Setting up Read the Docs shouldn’t be hard, as you just need to point your GitHub repo — or I think they are okay with a couple of other platforms — and they do the rest.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reflections
&lt;/h3&gt;

&lt;p&gt;Setting up Sphinx early on gave me more structure and helped me think about how others might use &lt;em&gt;stocksimpy&lt;/em&gt; in the future. It’s tempting to skip documentation at the beginning, but tools like Sphinx make it easy and rewarding.&lt;/p&gt;

&lt;h3&gt;
  
  
  What’s Next?
&lt;/h3&gt;

&lt;p&gt;In the next post, I’ll start building the main file structure as well as some basic indicators like SMA and RSI.&lt;/p&gt;




&lt;p&gt;🚀 Follow the Journey&lt;/p&gt;

&lt;p&gt;If you’re into Python, finance, open-source, or just love watching a dev project unfold — stick around!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/@suleymansade09/list/building-stocksimpy-944f16d39f68" rel="noopener noreferrer"&gt;building stocksimpy&lt;/a&gt; series&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🐈‍⬛ Star this on &lt;a href="https://github.com/SuleymanSade/StockSimPy" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🧠 Follow me on &lt;a href="https://x.com/SuleymanSade09" rel="noopener noreferrer"&gt;Twitter / X&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🔷 I’m now on &lt;a href="https://bsky.app/profile/suleymansade.bsky.social" rel="noopener noreferrer"&gt;Bluesky&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📰 Or read more of my posts on &lt;a href="https://medium.com/@suleymansade09" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;💬 Let’s connect on &lt;a href="https://www.linkedin.com/in/suleymansade/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks for reading — let me know how you would document your code, or would you use &lt;code&gt;sphinx&lt;/code&gt; too.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>python</category>
      <category>productivity</category>
      <category>learning</category>
    </item>
    <item>
      <title>🖼️Blog Cover Generator with Google AI Studio</title>
      <dc:creator>Suleyman Sade</dc:creator>
      <pubDate>Fri, 11 Jul 2025 02:36:07 +0000</pubDate>
      <link>https://dev.to/suleyman_sade/blog-cover-generator-with-google-ai-studio-26fa</link>
      <guid>https://dev.to/suleyman_sade/blog-cover-generator-with-google-ai-studio-26fa</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F35g8tviw3wtzmwbvhtnb.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F35g8tviw3wtzmwbvhtnb.jpeg" alt=" " width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This post is my submission for &lt;a href="https://dev.to/deved/build-apps-with-google-ai-studio"&gt;DEV Education Track: Build Apps with Google AI Studio&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;As someone who frequently writes blogs about 🤖 AI and programming. I decided to generate an app that uses Google Imagen to generate cover images for my blog posts.&lt;/p&gt;

&lt;p&gt;Here is the full user flow:&lt;br&gt;
✍️ The user inputs blog post content&lt;br&gt;
🧠 Gemini summarizes the theme and proposes a cover image description&lt;br&gt;
🎨 Imagen generates the cover image from Gemini's prompt&lt;br&gt;
🔁 The user gets to download or regenerate&lt;/p&gt;




&lt;p&gt;🧪 Here is the prompt that I used: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Create an app that would allow user to input their blog posts/article as a text input, analyze the information with Google Gemini and decide on an appropriate cover image description for the article, and build that cover image using Google Imagen. Give the user the option to download the image or generate a new image.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx2v1lpms3xmwbnbyce18.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx2v1lpms3xmwbnbyce18.gif" alt=" " width="80" height="47"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🧵 Try It Out
&lt;/h2&gt;

&lt;p&gt;Here’s the full source prompt in Google AI Studio:&lt;/p&gt;

&lt;p&gt;🔗 &lt;a href="https://aistudio.google.com/app/prompts?state=%7B%22ids%22:%5B%221T9oonLnvcZjcoOG3yDgBgN0ZcD6O_JFs%22%5D,%22action%22:%22open%22,%22userId%22:%22102277966606783211010%22,%22resourceKeys%22:%7B%7D%7D&amp;amp;usp=sharing" rel="noopener noreferrer"&gt;Launch the App in AI Studio&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  My Experience
&lt;/h2&gt;

&lt;p&gt;The resulting app was exactly what I wanted, but seeing it being coded by AI in just a couple of minutes - well, that was amazing.&lt;/p&gt;

&lt;p&gt;Big thanks 🙏 to DEV + Google AI Studio for making it easy (and free) to build cool ideas like this. This was a fast project, but one I’ll actually &lt;em&gt;use regularly&lt;/em&gt;.&lt;/p&gt;




&lt;p&gt;If you enjoyed reading:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🧠 Follow me on &lt;a href="https://x.com/SuleymanSade09" rel="noopener noreferrer"&gt;X/Twitter&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🔷 Follow me on &lt;a href="https://bsky.app/profile/suleymansade.bsky.social" rel="noopener noreferrer"&gt;Bluesky&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📰 Check out more of my work on &lt;a href="https://medium.com/@suleymansade09" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;💬 Let's connect on &lt;a href="https://www.linkedin.com/in/suleymansade/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>deved</category>
      <category>learngoogleaistudio</category>
      <category>ai</category>
      <category>gemini</category>
    </item>
    <item>
      <title>I am Building a Python Library from Scratch: Building StockSimPy | Week 0</title>
      <dc:creator>Suleyman Sade</dc:creator>
      <pubDate>Thu, 10 Jul 2025 20:55:23 +0000</pubDate>
      <link>https://dev.to/suleyman_sade/i-am-building-a-python-library-from-scratch-building-stocksimpy-week-0-5114</link>
      <guid>https://dev.to/suleyman_sade/i-am-building-a-python-library-from-scratch-building-stocksimpy-week-0-5114</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpp1usdm5ny4b6gcawmn8.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpp1usdm5ny4b6gcawmn8.webp" alt=" " width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🛠️ "The best way to learn to code is by building something real."&lt;/p&gt;

&lt;p&gt;That's the advice I have seen quite often, and now I am taking it seriously.&lt;/p&gt;

&lt;p&gt;I've decided to build &lt;strong&gt;StockSimPy&lt;/strong&gt;, a beginner-friendly Python library for simulating and testing stock trading strategies. &lt;/p&gt;

&lt;p&gt;So I am building:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A lightweight, open-source Python library
&lt;/li&gt;
&lt;li&gt;Focused on readability, simplicity, and education
&lt;/li&gt;
&lt;li&gt;Designed to help others along the way&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because most of the alternatives I found are generally very hard to use. I just want to create a simpler, educational alternative.&lt;/p&gt;

&lt;p&gt;This is not just about building something useful but also about leveling up my skills.&lt;/p&gt;




&lt;h2&gt;
  
  
  📖 What I hope to learn?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Python object-oriented design
&lt;/li&gt;
&lt;li&gt;How libraries are structured
&lt;/li&gt;
&lt;li&gt;Back testing logic
&lt;/li&gt;
&lt;li&gt;More about Pandas, NumPy and other data related libraries
&lt;/li&gt;
&lt;li&gt;Building real world projects
&lt;/li&gt;
&lt;li&gt;And much more…&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🔎 How I'm documenting?
&lt;/h2&gt;

&lt;p&gt;I am going to have at least 1 weekly log about my progress on the project, sometimes it might be more depending on my pace.&lt;/p&gt;

&lt;p&gt;The code is going to be on GitHub, and it will be updated with each post.&lt;/p&gt;

&lt;p&gt;I am going to talk about my mistakes and what I learned along the way.&lt;/p&gt;




&lt;h3&gt;
  
  
  Here is the GitHub link to the library (still in progress):
&lt;/h3&gt;

&lt;p&gt;🔗 &lt;a href="https://github.com/SuleymanSade/StockSimPy" rel="noopener noreferrer"&gt;GitHub - SuleymanSade/StockSimPy: A lightweight Python library for back testing stock strategies&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 Follow the Journey
&lt;/h2&gt;

&lt;p&gt;If you're into Python, finance, open-source, or just love watching a dev project unfold — stick around!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🧠 Follow me on &lt;a href="https://x.com/SuleymanSade09" rel="noopener noreferrer"&gt;X/Twitter&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🔷 Follow me on &lt;a href="https://bsky.app/profile/suleymansade.bsky.social" rel="noopener noreferrer"&gt;Bluesky&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📰 Check out more of my work on &lt;a href="https://medium.com/@suleymansade09" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;💬 Let's connect on &lt;a href="https://www.linkedin.com/in/suleymansade/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s build something cool together.&lt;br&gt;&lt;br&gt;
More updates coming in Week 1 — stay tuned.&lt;/p&gt;

</description>
      <category>devlog</category>
      <category>programming</category>
      <category>python</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
