<?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: Lucas Diogo</title>
    <description>The latest articles on DEV Community by Lucas Diogo (@lucasdiogo96).</description>
    <link>https://dev.to/lucasdiogo96</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%2F828790%2F5fa5ca7d-5efd-4904-a3d0-6ca5741aa38b.jpeg</url>
      <title>DEV Community: Lucas Diogo</title>
      <link>https://dev.to/lucasdiogo96</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/lucasdiogo96"/>
    <language>en</language>
    <item>
      <title>8 quick tips to improve your .NET API</title>
      <dc:creator>Lucas Diogo</dc:creator>
      <pubDate>Fri, 08 Apr 2022 20:01:28 +0000</pubDate>
      <link>https://dev.to/lucasdiogo96/8-quick-tips-to-improve-your-net-api-f36</link>
      <guid>https://dev.to/lucasdiogo96/8-quick-tips-to-improve-your-net-api-f36</guid>
      <description>&lt;p&gt;Every day we need to develop new APIs, whether at work or for study purposes, and some features can help us with the use of good practices in a simple way. And through this post, I want to show you some features that I use daily.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. API Versioning
&lt;/h2&gt;

&lt;p&gt;One of the challenges for those who build APIs is changing contracts that are already in use in the production environment. Clients may not want to update their applications when the API changes, so a versioning strategy becomes crucial.&lt;/p&gt;

&lt;p&gt;A versioning strategy allows clients to continue using the existing REST API and migrate their applications to the newer API when they are ready.&lt;/p&gt;

&lt;p&gt;In .NET, we can versioning our APIs through the &lt;em&gt;&lt;strong&gt;addApiVersioning&lt;/strong&gt;&lt;/em&gt;  extension.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2734%2F1%2AXm4KJ5RrCPmXqHa8AYtIMQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2734%2F1%2AXm4KJ5RrCPmXqHa8AYtIMQ.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This API versioning can be parameterized with some options, including the default version or even how the versioning will be done, whether by URL, header, or media type. For more details, you can access the &lt;a href="https://github.com/dotnet/aspnet-api-versioning/wiki/API-Documentation" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After the configuration performed above, it is necessary to inform the API version through the attribute. If it has been configured by URL, it will be necessary to parameterize it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2Ak85dzuMMXIXrPa8pSZqdgg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2Ak85dzuMMXIXrPa8pSZqdgg.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And in the API specification, you will get the following result.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3168%2F1%2AZwL76tVXXJsiTq5mXcDTCQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3168%2F1%2AZwL76tVXXJsiTq5mXcDTCQ.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Global Exception Handler
&lt;/h2&gt;

&lt;p&gt;Instead of creating lots of try-catch throughout the code to handle unexpected errors by our application, we can simply create a middleware that handles exceptions globally.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;br&gt;
And finally, use it.

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.UseMiddleware&amp;lt;ExceptionMiddleware&amp;gt;();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;You can check out more about how middleware works in .NET here: &lt;a href="https://docs.microsoft.com/en-us/aspnet/core/fundamentals/middleware/?view=aspnetcore-6.0" rel="noopener noreferrer"&gt;ASP.NET Core Middleware&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  3. Enable JWT in Swagger
&lt;/h2&gt;

&lt;p&gt;When our application uses bearer token authorization, to be able to test it in the swagger, it is necessary to perform the configuration below.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
After that, it will be possible to insert a JWT token generated for authorization in the swagger.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2608%2F1%2AACuJQld7Nb3-0bGK9vvGeg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2608%2F1%2AACuJQld7Nb3-0bGK9vvGeg.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Access HTTP information behind a proxy.
&lt;/h2&gt;

&lt;p&gt;When HTTPS requests are proxied over HTTP, the original scheme (HTTPS) is lost and must be forwarded in a header. Because an app receives a request from the proxy and not its true source on the Internet or corporate network, the originating client IP address must also be forwarded in a header.&lt;/p&gt;

&lt;p&gt;This happens even in environments like, for example, when we are trying to capture the IP address through HttpContext.Connection.RemoteIpAddress in a docker container application.&lt;/p&gt;

&lt;p&gt;For more information, you can access the link: &lt;a href="https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/proxy-load-balancer?view=aspnetcore-6.0" rel="noopener noreferrer"&gt;Configure ASP.NET Core to work with proxy servers and load balancers&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To solve it, we can use ForwardedHeaders middleware.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3054%2F1%2AeROBWb73JxCezcCBDt8hHA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3054%2F1%2AeROBWb73JxCezcCBDt8hHA.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And then use it.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.UseForwardedHeaders();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;After that, instead of getting the proxy’s IP, it will have the X-Forwarded-For header when the request is forwarded. With these settings, the application will replace by the IP forwarding in the header.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. IHttpContextAccessor instead of HTTP context
&lt;/h2&gt;

&lt;p&gt;The IHttpContextAccessor is an interface to access HTTP context in .NET, and because it uses dependency injection, it is extremely useful when we need some information in service layers.&lt;/p&gt;

&lt;p&gt;There are some good performance practices in its use. You can see it on the official Microsoft documentation: &lt;a href="https://docs.microsoft.com/en-us/aspnet/core/performance/performance-best-practices?view=aspnetcore-6.0" rel="noopener noreferrer"&gt;ASP.NET Core Performance Best Practices&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;First, we need to inject it.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;services.TryAddSingleton&amp;lt;IHttpContextAccessor,HttpContextAccessor();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2668%2F1%2ACVGHNNi7lhKno1HnUY01Cw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2668%2F1%2ACVGHNNi7lhKno1HnUY01Cw.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Check an example, accessing HTTP context by IHttpContextAccessor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2962%2F1%2AkK8XrMjlRhCpoIo3TUXrCw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2962%2F1%2AkK8XrMjlRhCpoIo3TUXrCw.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Problem Details
&lt;/h2&gt;

&lt;p&gt;An RFC called Problem Details (RFC7807) &lt;a href="https://datatracker.ietf.org/doc/html/rfc7807" rel="noopener noreferrer"&gt;Problem Details (RFC7807)&lt;/a&gt; standardizes how an error in an API should be responded to for the client. If you use &lt;a href="https://fluentvalidation.net/" rel="noopener noreferrer"&gt;Fluent validation&lt;/a&gt;, you may have noticed that the response is within this pattern.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AmU50ji9zEgpOZ9MHG83Urg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AmU50ji9zEgpOZ9MHG83Urg.png" alt="Response generates by fluent validation."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, there is a class that also implements this pattern, you can find the documentation here: &lt;a href="https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.problemdetails?view=aspnetcore-6.0" rel="noopener noreferrer"&gt;ProblemDetails Class&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As good implementation practices, it is always important to follow the patterns of some RFCs, it provides a better design.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. HTTP Logging
&lt;/h2&gt;

&lt;p&gt;HTTP Logging is a middleware that logs information about HTTP requests and responses. This middleware is extremely useful for visibility using logs, but it’s extremely important to keep two things in mind.&lt;/p&gt;

&lt;p&gt;Evaluate its use for sensitive data and that this middleware can reduce application performance, especially when logging the request and response bodies, so it is important to be aware of its configuration.&lt;/p&gt;

&lt;p&gt;You can find more about it in the documentation: &lt;a href="https://docs.microsoft.com/en-us/aspnet/core/fundamentals/http-logging/?view=aspnetcore-6.0" rel="noopener noreferrer"&gt;HTTP Logging in ASP.NET Core&lt;/a&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.UseHttpLogging();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2408%2F0%2AxwEjDep5pVDcM70Z" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2408%2F0%2AxwEjDep5pVDcM70Z" alt="(via Microsoft)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Health checks
&lt;/h2&gt;

&lt;p&gt;Health checks are exposed by an app as HTTP endpoints and are typically used with an external monitoring service or container orchestrator to check the status of an app. Before adding health checks to an app, decide on which monitoring system to use. The monitoring system dictates what types of health checks to create and how to configure their endpoints.&lt;/p&gt;

&lt;p&gt;You can add the following code to the pipeline:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;builder.Services.AddHealthChecks();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Here is an example implementation in the official Microsoft documentation:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AcrM32CvmwUOkJM08USo4Nw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AcrM32CvmwUOkJM08USo4Nw.png" alt="(via Microsoft)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In addition to exporting a health check, you can also use a UI to monitor all of your endpoints and even database connections.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2064%2F1%2ATFSLLACeyoKGalQtAWL95A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2064%2F1%2ATFSLLACeyoKGalQtAWL95A.png" alt="via Github(Xabaril)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The following example demonstrates the layout of the health checker UI:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3200%2F0%2AlXUYt5Htm6WDwTrF.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3200%2F0%2AlXUYt5Htm6WDwTrF.png" alt="via Github(Xabaril)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Above are listed some main components and patterns that I use in my day-to-day when building APIs. NET.&lt;/p&gt;

&lt;p&gt;Hope you like it, see you in the next article.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F0%2AP-ivLQTgc53F2sEZ.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F0%2AP-ivLQTgc53F2sEZ.gif" alt="That’s all folks!"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;References:&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;**Dotnet API Versioning: &lt;a href="https://github.com/dotnet/aspnet-api-versioning/wiki/API-Documentation" rel="noopener noreferrer"&gt;**https://github.com/dotnet/aspnet-api-versioning/wiki/API-Documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Configure ASP.NET Core to work with proxy servers and load balancers:&lt;/strong&gt; &lt;a href="https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/proxy-load-balancer?view=aspnetcore-6.0" rel="noopener noreferrer"&gt;https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/proxy-load-balancer?view=aspnetcore-6.0&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Access HttpContext in ASP.NET Core:&lt;/strong&gt; &lt;a href="https://docs.microsoft.com/en-us/aspnet/core/fundamentals/http-context?view=aspnetcore-6.0" rel="noopener noreferrer"&gt;https://docs.microsoft.com/en-us/aspnet/core/fundamentals/http-context?view=aspnetcore-6.0&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Problem Details for HTTP APIs:&lt;/strong&gt; &lt;a href="https://datatracker.ietf.org/doc/html/rfc7807" rel="noopener noreferrer"&gt;https://datatracker.ietf.org/doc/html/rfc7807&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HTTP Logging in ASP.NET Core:&lt;/strong&gt; &lt;a href="https://docs.microsoft.com/en-us/aspnet/core/fundamentals/http-logging/?view=aspnetcore-6.0" rel="noopener noreferrer"&gt;https://docs.microsoft.com/en-us/aspnet/core/fundamentals/http-logging/?view=aspnetcore-6.0&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Health checks in ASP.NET Core:&lt;/strong&gt; &lt;a href="https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/health-checks?view=aspnetcore-6.0" rel="noopener noreferrer"&gt;https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/health-checks?view=aspnetcore-6.0&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ProblemDetails Class:&lt;/strong&gt; &lt;a href="https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.problemdetails?view=aspnetcore-6.0" rel="noopener noreferrer"&gt;https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.problemdetails?view=aspnetcore-6.0&lt;/a&gt;&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>api</category>
    </item>
    <item>
      <title>Predição de ações na bolsa de valores com Python e Facebook Prophet</title>
      <dc:creator>Lucas Diogo</dc:creator>
      <pubDate>Thu, 24 Mar 2022 03:46:45 +0000</pubDate>
      <link>https://dev.to/lucasdiogo96/predicao-de-acoes-na-bolsa-de-valores-com-python-e-facebook-prophet-bli</link>
      <guid>https://dev.to/lucasdiogo96/predicao-de-acoes-na-bolsa-de-valores-com-python-e-facebook-prophet-bli</guid>
      <description>&lt;h2&gt;
  
  
  Predição de ações na bolsa de valores com Python e Facebook Prophet
&lt;/h2&gt;

&lt;p&gt;Usando Machine Learning para projetar valores futuros.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3400%2F1%2Akf5IyvHytnUizG6viM2AMQ.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3400%2F1%2Akf5IyvHytnUizG6viM2AMQ.jpeg" alt="(Crédito: B3/Divulgação)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Em meio a pandemia da COVID 19 e a crise econômica muitas pessoas (inclusive eu) começaram a despertar o interesse por investir em renda variável na bolsa de valores, quantidade de pessoas essa que cresceu exponencialmente nos últimos 3 anos, e hoje em 2022 a B₃(BM&amp;amp;FBOVESPA) contabiliza a marca de &lt;a href="https://www.b3.com.br/pt_br/noticias/5-milhoes-de-contas-de-investidores.htm" rel="noopener noreferrer"&gt;5 milhões de contas físicas cadastradas&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2Ad4_yBWc0IhrBQ9JrYPG83Q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2Ad4_yBWc0IhrBQ9JrYPG83Q.png" alt="Evolução de quantidade de pessoas físicas cadastradas na B3. Fonte: B3"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  O que é bolsa de valores?
&lt;/h2&gt;

&lt;p&gt;A bolsa de valores é um ambiente de negociação onde investidores podem **negociar **seus títulos emitidos por empresas, sejam elas com capitais públicos, mistos ou privados. Esse processo é intermediado com auxílio de correspondentes de negociações através de corretoras.&lt;/p&gt;

&lt;p&gt;Operar nesse mercado sem conhecimento prévio pode ser bastante complexo, principalmente porque no papel de acionista é extremamente importante realizar o acompanhamento, fazer análises fundamentalistas sobre a empresa e o momento, para somente após isso decidir aonde colocará o seu suado dinheiro.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cenário
&lt;/h2&gt;

&lt;p&gt;Atualmente machine learning (e até mesmo redes neurais) tem entrado nos “trend topics” de investimento, pois investidores buscam automatizar não todo, mas parte do processo, pois é uma área que estuda a capacidade de aprendizado de um computador sobre conjuntos de dados e vem sendo muito utilizado para construção de robôs operacionais na área de investimentos.&lt;/p&gt;

&lt;p&gt;Em minhas recentes pesquisas sobre o assunto encontrei alguns modelos de implementação utilizando a &lt;a href="https://scikit-learn.org/stable/index.html" rel="noopener noreferrer"&gt;SciKit Learn&lt;/a&gt; (biblioteca para aprendizado de máquina em python) com métodos de regressão que buscam predizer valores de ações na bolsa.&lt;/p&gt;

&lt;p&gt;O problema de todas as implementações e o maior erro em minha opinião é que, na verdade, não estão predizendo nada, deixe me explicar.&lt;/p&gt;

&lt;p&gt;A maior parte dos exemplos faz a divisão dos dados de uma ação em treinamento e teste limitando a um simples aprendizado para “predições” de dados históricos. E quando falamos em predição de valores na bolsa, também temos em mente a projeção para datas futuras, pois queremos saber qual o valor que terá uma determinada ação em um determinado dia, o que não é abordado.&lt;/p&gt;

&lt;p&gt;Em busca de uma solução para o problema encontrei o Prophet, uma biblioteca criada pelo Facebook com implementações em R e Python para fornecer previsões automatizadas, e é com ela que trabalharemos.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Pré processamento&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Como requisito, precisaremos das bibliotecas listadas abaixo, as instruções de instalação das mesmas podem ser encontradas nos links.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://pandas.pydata.org/" rel="noopener noreferrer"&gt;Pandas&lt;/a&gt;: Manipulação de dataframes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/twopirllc/pandas-ta" rel="noopener noreferrer"&gt;Pandas T.A&lt;/a&gt;: Biblioteca Pandas para análise técnica.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://pypi.org/project/yahooquery/" rel="noopener noreferrer"&gt;Yahoo Query&lt;/a&gt;: Busca de dados do mercado financeiro.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://plotly.com/" rel="noopener noreferrer"&gt;Plotly&lt;/a&gt;: Visualização de gráficos.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://facebook.github.io/prophet/" rel="noopener noreferrer"&gt;Prophet&lt;/a&gt;: Automação preditiva.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No primeiro passo, realizaremos a importação das bibliotecas necessárias.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;br&gt;
Após então, utilizaremos o &lt;a href="https://github.com/dpguthrie/yahooquery" rel="noopener noreferrer"&gt;yahooquery &lt;/a&gt;que é uma biblioteca excelente para realizar extrações de dados do mercado financeiro do site &lt;a href="https://finance.yahoo.com/" rel="noopener noreferrer"&gt;Yahoo Finance&lt;/a&gt; e nos devolve informações extremamente úteis com rapidez e facilidade. Realizaremos uma busca dos dados de pregão de uma determinada ação na bolsa de valores e após isso o devido pré processamento.&lt;br&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;br&gt;
**Linha 1: **A informação que está sendo atribuída a variável symbol é a identificação do ativo. Você irá achar esse código acessando o &lt;a href="https://finance.yahoo.com/" rel="noopener noreferrer"&gt;Yahoo Finance&lt;/a&gt;.

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AcNbkcI2UkATyKhoojAeK_g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AcNbkcI2UkATyKhoojAeK_g.png" alt="Yahoo Finance: [https://finance.yahoo.com/](https://finance.yahoo.com/)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;**Linha 8. **Realização da busca referente ao ativo em um período determinado, no caso escolhido foi 48 meses.&lt;/p&gt;

&lt;p&gt;**Linha 10. **Esse dataframe possui dois índices, o primeiro é o código do ativo e o segundo a data do pregão, removeremos o primeiro.&lt;/p&gt;

&lt;p&gt;**Linha 14. **Aqui copiamos o índex de data para uma coluna no nosso dataframe e por fim reindexamos novamente.&lt;/p&gt;

&lt;p&gt;**Linha 20. **Cópia das features de interesse para um novo dataframe.&lt;/p&gt;

&lt;p&gt;**Linha 23. **Existem diversas análises técnicas que podemos fazer para acompanhar o valor de uma ação, no nosso caso optaremos pela **Exponential Move Avarage (EMA) **utilizando 21 dias como amostra.&lt;/p&gt;

&lt;p&gt;Exponential Move Avarage ou também conhecido por média móvel, é semelhante à média móvel simples (SMA), que mede a direção da tendência ao longo de um período. No entanto, enquanto a SMA simplesmente calcula uma média dos dados de preços, a EMA aplica mais peso aos dados mais atuais. Devido ao seu cálculo exclusivo, a EMA seguirá os preços mais de perto do que uma SMA.&lt;/p&gt;

&lt;p&gt;Esse cálculo é feito pelo Pandas TA que é a biblioteca escolhida por conter a maioria das análises técnicas implementadas.&lt;/p&gt;

&lt;p&gt;Após o pré processamento, este será o nosso dataframe com o qual trabalharemos.&lt;/p&gt;

&lt;p&gt;Para obter uma melhor visualização, realizamos a plotagem da informação dos nossos dados em gráfico.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;br&gt;
Aqui podemos observar mais nitidamente o desempenho do valor da ação temporalmente.

&lt;h2&gt;
  
  
  Processamento
&lt;/h2&gt;

&lt;p&gt;Nessa segunda etapa prepararemos nosso modelo utilizando técnicas de Machine Learning para predizer os valores de ações com base em uma projeção de x dias.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;br&gt;
**Linha 2. **Seleciona features que vão compor o treinamento do modelo.

&lt;p&gt;**Linha 7. **Instanciado o Prophet com parâmetro baseado em cálculo diário.&lt;/p&gt;

&lt;p&gt;**Linha 14. **Treinamento no modelo com base no dataframe. Note que estamos usando todos os dados e não particionando-os, pois a ideia é que utilizemos todo como treinamento, e a projeção como teste.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Linha 16.&lt;/strong&gt; Removemos os finais de semana da nossa projeção, pois não há pregões nesses dias e pode interferir no resultado.&lt;/p&gt;

&lt;p&gt;Se acompanharmos no console enquanto o nosso modelo é treinado, podemos visualizar algumas informações úteis como o número de iterações realizadas no aprendizado.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2028%2F1%2A9RpeYKZjzYLHszBdyFSZWg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2028%2F1%2A9RpeYKZjzYLHszBdyFSZWg.png" alt="Treinamento visualizado no console."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;**Linha 20. **Criação da projeção para os próximos 30 dias após a última data de pregão do dataset.&lt;/p&gt;

&lt;p&gt;**Linha 23. **Nesse momento, o modelo irá tentar predizer os valores com base no que aprendeu previamente no seu treinamento e irá nos retornar o valor do ativo projetado para o tempo estipulado.&lt;/p&gt;

&lt;p&gt;Para entendermos melhor, iremos plotar os resultados em um gráfico.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;br&gt;
Após isso conduziremos uma breve análise.

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AAjTtNzM29F-9Sxz-0YhnNA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AAjTtNzM29F-9Sxz-0YhnNA.png" alt="Gráfico da regressão realizada onde os pontos em preto são os dados já observados e a linha azul é a predição."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Se olharmos atentamente ao gráfico veremos que nos próximos 30 dias não possuímos nenhuma comparação de valor atual, mas sim somente a linha de predição e é exatamente aqui que está contido a informação de valores futuros.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2ATzozqBpxRswl7Mo17lExVQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2ATzozqBpxRswl7Mo17lExVQ.png" alt="Valores projetados"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A variável forecast possui os dados da predição, utilizaremos ela para filtrar por registros com a data maiores que a atual a nossa projeção para um dataframe.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;br&gt;
Aqui está o resultado:

&lt;p&gt;Como removemos os finais de semana, sobraram na nossa projeção 20 dias úteis com o respectivo valor de fechamento.&lt;/p&gt;

&lt;h2&gt;
  
  
  Validação
&lt;/h2&gt;

&lt;p&gt;Para avaliar o desempenho do nosso modelo é preciso elaborar algumas validações e destacar algumas métricas de assertividade.&lt;/p&gt;

&lt;p&gt;A validação cruzada é uma técnica usada com frequência no machine learning para avaliar a variabilidade de um conjunto de dados e a confiabilidade dos modelos treinado com esses dados.&lt;/p&gt;

&lt;p&gt;O Prophet inclui uma funcionalidade para validação cruzada de séries temporais para medir o erro de previsão usando dados históricos. Isso é feito selecionando pontos de corte no histórico, e para cada um deles ajustando o modelo usando dados somente até aquele ponto de corte. Assim, você pode entender se o modelo é suscetível a variações nos dados.&lt;/p&gt;

&lt;p&gt;Executando o código abaixo obteremos o resultado da cross-validation e das métricas de desempenho do modelo.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;br&gt;
E esses são os resultados de desempenho do nosso modelo.

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2Anjc4iDgrFG2iSqwv_Jd3ww.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2Anjc4iDgrFG2iSqwv_Jd3ww.png" alt="Execução da validação cruzada"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As métricas geradas podem também ser visualizas em gráfico.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AM0UCsfHKpzfMNQhTmnWNDA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AM0UCsfHKpzfMNQhTmnWNDA.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O código completo pode ser encontrado no meu Github:&lt;br&gt;
&lt;a href="https://github.com/LucasDiogo96/Stock-Market-Prediction" rel="noopener noreferrer"&gt;&lt;strong&gt;GitHub — LucasDiogo96/Stock-Market-Prediction&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O valor de mercado de uma ação na bolsa de valores também pode ser afetado por fatores externos ao de uma análise, como uma decisão política ou uma pandemia como foi o ano de 2020.&lt;/p&gt;

&lt;p&gt;Da mesma forma, com o avanço constante na área de aprendizado de máquina, estamos munidos de cada vez mais ferramentas e técnicas para automatizar análises que nos ajudem a garantir um bom desempenho como acionistas.&lt;/p&gt;

&lt;p&gt;Hora de ficar rico, até a próxima!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2ALCJmeYc_63MaZA7CkbcaEQ.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2ALCJmeYc_63MaZA7CkbcaEQ.gif" alt="Time is money"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Referências:
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;O que é bolsa de valores e como funciona:&lt;/strong&gt; &lt;a href="https://www.btgpactualdigital.com/como-investir/artigos/investimentos/tudo-sobre-bolsa-de-valores" rel="noopener noreferrer"&gt;https://www.btgpactualdigital.com/como-investir/artigos/investimentos/tudo-sobre-bolsa-de-valores&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5 milhões de contas de investidores:&lt;/strong&gt; &lt;a href="https://www.b3.com.br/pt_br/noticias/5-milhoes-de-contas-de-investidores.htm" rel="noopener noreferrer"&gt;https://www.b3.com.br/pt_br/noticias/5-milhoes-de-contas-de-investidores.htm&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Exponential Moving Average:&lt;/strong&gt; &lt;a href="https://www.fidelity.com/learning-center/trading-investing/technical-analysis/technical-indicator-guide/ema" rel="noopener noreferrer"&gt;https://www.fidelity.com/learning-center/trading-investing/technical-analysis/technical-indicator-guide/ema&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cross-validation: evaluating estimator performance:&lt;/strong&gt; &lt;a href="https://scikit-learn.org/stable/modules/cross_validation.html" rel="noopener noreferrer"&gt;https://scikit-learn.org/stable/modules/cross_validation.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;B3 atinge 5 milhões de contas de investidores em renda variável em janeiro:&lt;/strong&gt; &lt;a href="https://www.b3.com.br/pt_br/noticias/5-milhoes-de-contas-de-investidores.htm" rel="noopener noreferrer"&gt;https://www.b3.com.br/pt_br/noticias/5-milhoes-de-contas-de-investidores.htm&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>stocks</category>
      <category>datascience</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>Desmistificando roteirizações com Python</title>
      <dc:creator>Lucas Diogo</dc:creator>
      <pubDate>Thu, 24 Mar 2022 03:37:02 +0000</pubDate>
      <link>https://dev.to/lucasdiogo96/desmistificando-roteirizacoes-com-python-2bo0</link>
      <guid>https://dev.to/lucasdiogo96/desmistificando-roteirizacoes-com-python-2bo0</guid>
      <description>&lt;h2&gt;
  
  
  Desmistificando roteirizações com Python
&lt;/h2&gt;

&lt;p&gt;Uma abordagem completa de como otimizar sua frota.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2A5LxVqxbEfqG18Rc2X16GQA.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2A5LxVqxbEfqG18Rc2X16GQA.jpeg" alt="Fonte: DHL"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Atualmente nos Estados Unidos, estima-se que exista 1,2 milhões de empresas de transporte rodoviário responsáveis por cerca de 70% do frete anualmente no país, representando US$ 671 bilhões em mercadorias transportadas por caminhões. Esse segmento levanta uma receita total de aproximadamente 255 bilhões de dólares.&lt;/p&gt;

&lt;p&gt;Uma frota de caminhões pode passar por diversos postos de coletas/entregas diariamente, e para isso existe um conceito chamado &lt;strong&gt;roteirização&lt;/strong&gt;, que serve basicamente como um mapa logístico que define o caminho que cada motorista irá percorrer para cumprir o seu objetivo e traz diversos benefícios como:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Redução de custo:&lt;/strong&gt; Indicando o caminho mais curto a se fazer no dia, economizando combustível e distância percorrida, podendo reduzir até 20% nos custos de entrega.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Aumento de produtividade:&lt;/strong&gt; Traz melhor visibilidade na distribuição de pontos de coleta para cada veículo fazendo com que a não haja discrepância em distâncias, por exemplo, ao invés de deslocar um caminhão X para atender o ponto Y que está 1000 KM de distância, o caminhão Z a 100 KM será designado para atender o ponto Y pois está mais perto, podendo até mesmo aumentar o número de entregas no mês.&lt;/p&gt;

&lt;p&gt;**Satisfação do cliente: **Quanto mais otimizado for o processo de deslocamento na cadeia de suprimentos até chegar ao cliente final, mais satisfeito ele estará por receber sua mercadoria rápido.&lt;/p&gt;

&lt;p&gt;Após uma breve introdução, antes de partirmos para a parte prática, precisamos conhecer os problemas computacionais que envolvem a construção do nosso roteirizador.&lt;/p&gt;

&lt;p&gt;Quando falamos de otimização de rotas, temos como referência o &lt;a href="https://en.wikipedia.org/wiki/Vehicle_routing_problem" rel="noopener noreferrer"&gt;Vehicle Routing Problem (VRP)&lt;/a&gt; e o &lt;a href="https://en.wikipedia.org/wiki/Travelling_salesman_problem" rel="noopener noreferrer"&gt;Travelling Salesman Problem (TSP)&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  TSP (Travel salesman problem)
&lt;/h2&gt;

&lt;p&gt;O travel salesman problem, também conhecido por “O problema do caixeiro viajante” é um dos problemas mais conhecidos na área de ciência da computação e pesquisa operacional.&lt;/p&gt;

&lt;p&gt;Consiste em, dado um conjunto de cidades e suas posições, o problema é encontrar o caminho mais curto para que cada cidade seja visitada apenas uma vez e, finalmente, retorne ao ponto de partida.&lt;/p&gt;

&lt;p&gt;No entanto, a medida que o número de destinos aumenta, o número correspondente de combinações de viagens de ida e volta pode exceder a capacidade de até mesmo computadores com grande poder de processamento, pois com 10 destinos o número de cálculos pode chegar a 300.000 combinações, já com 15 destinos pode ultrapassar 87 bilhões.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AWO8ZRNtPim5UiYTJRduADQ.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AWO8ZRNtPim5UiYTJRduADQ.gif" alt="Fonte: YouTube. (18, Agosto 2013). [Traveling Salesman Problem.](https://www.youtube.com/watch?v=SC5CX8drAtU)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  VRP (Vehicle Routing Problem)
&lt;/h2&gt;

&lt;p&gt;No problema de VRP, ou também conhecido “Problema de roteamento de veículos”, o objetivo é encontrar rotas otimizadas para vários veículos que visitam um conjuntos de localizações (quando é somente um veículo o problema é o TSP), considerando restrições específicas do negócio como, limitações de veículos, recursos, janela de tempo entre outros. Esse problema possui outras variantes que não iremos abordar no nosso exemplo, mas que são facilmente extensíveis para implementação.&lt;/p&gt;

&lt;p&gt;São elas as mais famosas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Vehicle Routing Problem with Time Windows (VRPTW)&lt;/strong&gt;: Os locais de entrega têm janelas de tempo dentro das quais as entregas (ou visitas) devem ser feitas.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Capacitated Vehicle Routing Problem: CVRP or CVRPTW&lt;/strong&gt;. Os veículos têm uma capacidade de transporte limitada das mercadorias que devem ser entregues.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Vehicle Routing Problem with Multiple Trips (VRPMT)&lt;/strong&gt;:Os veículos podem fazer mais de uma rota.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Open Vehicle Routing Problem (OVRP)&lt;/strong&gt;: Os veículos não são obrigados a retornar ao depósito.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Inventory Routing Problem (IRP)&lt;/strong&gt;: Os veículos são responsáveis ​​por atender as demandas em cada ponto de entrega.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Multi-Depot Vehicle Routing Problem (MDVRP)&lt;/strong&gt;: Existem vários depósitos a partir dos quais os veículos podem começar e terminar.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A otimização é baseada em uma abordagem heurística que não garante a solução perfeita, porém, se bem configurada, pode nos fornecer ótimas soluções em pouco tempo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2A3c3m29FrgKddlinGgjaxQg.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2A3c3m29FrgKddlinGgjaxQg.jpeg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Agora iremos para a melhor parte, e ao decorrer da implementação irei me aprofundando em alguns conceitos.&lt;/p&gt;

&lt;p&gt;O nosso exemplo irá se basear em VRP e terá como premissa 6 veículos que deverão visitar todos os 49 estados americanos (o Havaí e o Alaska não estão na lista, pois são possíveis outliers já que estão muito distante dos demais).&lt;/p&gt;

&lt;p&gt;Como requisito, necessitaremos das bibliotecas listadas abaixo, a instrução de instalação das mesmas pode ser encontrado nos links.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://pandas.pydata.org/" rel="noopener noreferrer"&gt;Pandas&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://numpy.org/" rel="noopener noreferrer"&gt;Numpy&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://scikit-learn.org/" rel="noopener noreferrer"&gt;Scikit-learn&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://developers.google.com/optimization" rel="noopener noreferrer"&gt;OrTools&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://plotly.com/" rel="noopener noreferrer"&gt;Plotly&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Após instalado os pacotes necessários, em nosso notebook jupyter iremos importa-los como mostrado abaixo.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;br&gt;
Após a importação das nossas bibliotecas , será necessário a obtenção dos dados dos nossos pontos de visita e dos nossos veículos.&lt;br&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;br&gt;
Basicamente nesse trecho de código fizemos o seguinte:

&lt;p&gt;&lt;strong&gt;Linha 2 :&lt;/strong&gt; Importamos os dados contendo a informação de latitude e longitude de todos os estados americanos usando pandas.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Linha 5:&lt;/strong&gt; Removemos os nossos estados “outliers” no caso Alaska e Havaí por serem muito distante dos demais.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Linha 8:&lt;/strong&gt; Criamos os dados dos seis veículos contendo somente nome e placa.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;13 a 22:&lt;/strong&gt; Utilizaremos 6 estados americanos randomicamente para ser o nosso ponto de partida e chegada dos nossos veículos e adicionamos a informação de latitude e longitude ao dataframe. Os dados amostrados como ponto de partida retiramos do dataset de estados americanos pois teoricamente os veículos já estarão partindo deles então não é necessário uma visita, o que restará 6 veículos e 43 pontos de visitas.&lt;/p&gt;

&lt;p&gt;Os nossos dados ao final terão o seguinte formato:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AfIwNWPzm3mAgVoQ7iEgknQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AfIwNWPzm3mAgVoQ7iEgknQ.png" alt="A esquerda uma pequena amostragem dos dados de estados americanos (pontos de visita). A direita os nossos veículos que iremos utilizar para atender todos os 43 pontos restantes do dataset de estados."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Após a obtenção dos dados entraremos na etapa de pré-processamento, ou seja, iremos realizar o tratamento necessário em nossos dados antes de processa-los.&lt;/p&gt;

&lt;p&gt;Mas antes disso, explicarei como é feito o processo de otimização por baixo dos panos.&lt;/p&gt;

&lt;p&gt;1- Calculamos as distancias de todas as localizações envolvidas no processo e envolvendo também os pontos de partida e chegada e isso pode ser feito através de uma &lt;a href="https://pt.wikipedia.org/wiki/Matriz_de_dist%C3%A2ncias" rel="noopener noreferrer"&gt;&lt;strong&gt;matriz de distância&lt;/strong&gt;s&lt;/a&gt;&lt;strong&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A matriz de distancias é uma matriz bidimensional que contem todas as distancias correlacionadas.&lt;/p&gt;

&lt;p&gt;Suponha que você tenha 5 locais A, B, C, D e E, então a matriz de distância consiste em todas as 20 distâncias (5*5–5)&lt;/p&gt;

&lt;p&gt;No nosso exemplo temos 55 locais (6 locais de partida, 6 locais de chegada,43 pontos de visita) ou seja, uma matriz de 2.970 combinações.&lt;/p&gt;

&lt;p&gt;2- Com base na matriz, os pontos de visita são atribuídos aos veículos, que em seguida para cada veículo no problema, é atribuída uma rota de modo que a função objetivo especificada seja minimizada. É usado então uma heurística com base no &lt;a href="https://en.wikipedia.org/wiki/Nearest_neighbor_search" rel="noopener noreferrer"&gt;vizinho mais próximo (NNS)&lt;/a&gt; que combina elementos de algoritmos de recozimento simulado e de aceitação de limiar.&lt;/p&gt;

&lt;p&gt;Funciona da seguinte maneira:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Partindo de uma solução inicial, a mesma é quebrada em várias partes onde obtemos:&lt;/li&gt;
&lt;li&gt;Um conjunto de pontos de visita que não são mais atendidas por um veículo.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Solução parcial contendo todas as outras entregas.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Com base na solução parcial, todas os pontos de visita do conjunto são incluídos novamente, gerando uma nova solução. Se a nova solução for boa, ela é aceita como a nova melhor solução quando uma nova iteração de recriação é iniciada. Essas etapas são repetidas várias vezes até que um determinado critério de término seja atendido, por exemplo: Tempo de processamento ou número de iterações&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Linha 1 a 17:&lt;/strong&gt; Aqui criei um método onde separo todos os dados de geolocalização (latitude e longitude) em partida, chegada, pontos de visita e por último, uma contendo todas as geolocalizações, que será necessário para montar nossa matriz de distâncias. Note que na linha 15 é utilizado a função do &lt;a href="https://numpy.org/doc/stable/reference/generated/numpy.radians.html" rel="noopener noreferrer"&gt;Numpy radians&lt;/a&gt; onde contém todas as localizações. Isso serve para normalizar os nossos dados e ter uma melhor desempenho no cálculo.&lt;/p&gt;

&lt;p&gt;**Linha 21 a 27: **Aqui é apenas um método para montar um DTO contendo algumas informações para passarmos para o nosso método que será responsável por processar a o problema e nos entregar uma solução.&lt;/p&gt;

&lt;p&gt;**Linha 30 a 32: **Aqui é onde utilizamos as nossas coordenadas para criar a matriz de distâncias utilizando a classe &lt;a href="https://scikit-learn.org/0.24/modules/generated/sklearn.neighbors.DistanceMetric.html" rel="noopener noreferrer"&gt;DistanceMetric&lt;/a&gt;, onde é possível selecionar o tipo de métrica para a construção dessa matriz.&lt;/p&gt;

&lt;p&gt;Em ciência de dados existem várias formas de calcular distâncias, por exemplo: em linha reta (euclidiana), em curvatura como um globo (haversine) entre outras. Todas elas possuem uma fórmula matemática diferente para serem calculadas e ao todo são 9. Para saber mais você pode &lt;a href="https://towardsdatascience.com/9-distance-measures-in-data-science-918109d069fa?gi=3b78c5992c87" rel="noopener noreferrer"&gt;clicar aqui.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2Alwmhp4P2URCga7eXUuu-fw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2Alwmhp4P2URCga7eXUuu-fw.png" alt="Fonte: 9 medidas de distância em ciência de dados. Fonte: Marten Grootendorst/[Medium](https://towardsdatascience.com/9-distance-measures-in-data-science-918109d069fa)."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Na etapa de processamento vamos utilizar o Google &lt;a href="https://developers.google.com/optimization" rel="noopener noreferrer"&gt;OR-Tools&lt;/a&gt; que será responsável por definitivamente resolver o problema de VRP.&lt;/p&gt;

&lt;p&gt;A implementação desse método você encontra na documentação da própria biblioteca.&lt;/p&gt;

&lt;p&gt;Porém, irei comentar sobre alguns parâmetros usados que valem como ponto de atenção.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;br&gt;
&lt;strong&gt;Linha 5: *&lt;em&gt;Nessa linha note ser passado por parâmetro os *&lt;/em&gt;&lt;/strong&gt;dados que pré processamos anteriormente para o método RoutingIndexManager do OR Tools.

&lt;p&gt;**Linha 40: **Já aqui é definido o limite de tempo em segundos que será gasto no processamento, pois como comentado anteriormente, será realizado vários ciclos em busca procurando pela melhor solução para o problema, e quanto mais elementos temos, mais pesado é o processamento logo, definir um tempo limite é importante.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Linha 43:&lt;/strong&gt; Esse parâmetro é utilizado para visualizarmos os logs para entendermos melhor como está sendo realizado o processo dessa busca da solução. Se olharmos atentamente aos logs veremos algumas informações como o número de soluções geradas, tempo, ramificações, memória utilizada para gerar a solução entre outras…&lt;/p&gt;

&lt;p&gt;Observação: Note ser utilizado cerca de 200 MB de memória para cada solução gerada.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3164%2F1%2A7YavP7LQxItYVhIp3_et4g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3164%2F1%2A7YavP7LQxItYVhIp3_et4g.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;**Linha 51: **O número passado como parâmetro é a distância máxima (em milhas) que cada veículo poderá percorrer em cada rota.&lt;/p&gt;

&lt;p&gt;Ao final do processamento teremos já o VRP resolvido com as rotas definidas para cada veículo. Após isso precisamos estruturar a resposta, ou seja, realizar um pós processamento.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;br&gt;
&lt;strong&gt;Linha 3:&lt;/strong&gt; O método MapResult será responsável por converter a resposta obtida no processamento para dados estruturados, retornando assim, uma lista de dataframes, onde cada um possuirá a rota de um veículo.

&lt;p&gt;&lt;strong&gt;Linha 58:&lt;/strong&gt; Através do uso de índices e dos dados originais, esse método é responsável por mapear para dataframe.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Linha 82:&lt;/strong&gt; A medida que o OR Tools utiliza é milhas, aqui definimos uma pequena função para a nossa resposta sair em quilômetros.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Linha 87 a 90:&lt;/strong&gt; Caso o processamento não tenha sucesso em sua busca pela solução do problema, é definido uma mensagem de falha e encerramento do fluxo, caso contrário realizaremos o pós processamos da nossa resposta.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Linha 93:&lt;/strong&gt; Aqui concatenamos todas os dataframes para termos a visão completa da roteirização realizada, e esse é o resultado:&lt;/p&gt;

&lt;p&gt;Se observarmos os dados atentamente, a primeira e ultima linha de cada veículo será o mesmo local, pois representam o local de partida e chegada respectivamente.&lt;/p&gt;

&lt;p&gt;E para fechar com chave de ouro, vamos criar um método para visualizar essa distribuição no mapa.&lt;/p&gt;

&lt;p&gt;Para fazer isso, utilizarei o &lt;a href="https://www.mapbox.com/" rel="noopener noreferrer"&gt;MapBox&lt;/a&gt; para trabalhar com dados de geolocalização. Siga os seguintes passos:&lt;/p&gt;

&lt;p&gt;1- Crie uma conta na plataforma clicando &lt;a href="https://account.mapbox.com/auth/signup/" rel="noopener noreferrer"&gt;aqui &lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;2- Após logar, na aba &lt;strong&gt;Tokens&lt;/strong&gt;, crie um novo token&lt;/p&gt;

&lt;p&gt;3- Copie o token gerado e cole, atribuindo o token a variável &lt;strong&gt;mapbox_token&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;br&gt;
E finalmente:

&lt;p&gt;Cada cor representa um veículo, e as numerações são as ordens de quais pontos devem ser visitados.&lt;/p&gt;

&lt;p&gt;Podemos ir ainda mais além na nossa visualização e utilizar por exemplo uma API de directions para desenhar a rota no mapa.&lt;/p&gt;

&lt;p&gt;O código completo pode ser encontrado aqui no meu Github:&lt;br&gt;
&lt;a href="https://github.com/LucasDiogo96/Routing-Optimizer" rel="noopener noreferrer"&gt;&lt;strong&gt;GitHub — LucasDiogo96/Routing-Optimizer: This solution was written in python and is based on the…&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Um planejamento efetivo de rotas é primordial para qualquer empresa de entregas. Mais que definir uma sequência de entregas, &lt;strong&gt;é necessário elaborar um planejamento realista considerando as principais variáveis do negócio&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Para garantir a efetividade é preciso investir em dois quesitos fundamentais: tecnologia e planejamento. Justamente por unir ambas que o *&lt;em&gt;roteirizador *&lt;/em&gt;é tão importante, e acaba se tornando a peça chave para estar à frente dos concorrentes e manter a competitividade no mercado.&lt;/p&gt;

&lt;p&gt;Até a próxima !!!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2Az-h_1fbl93DvI0Ub1FOnpQ.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2Az-h_1fbl93DvI0Ub1FOnpQ.gif" alt="That’s all folks! Nos vemos em breve em um próximo post."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Referências:
&lt;/h2&gt;

&lt;p&gt;Truck Info: &lt;a href="https://www.truckinfo.net/research/trucking-statistics" rel="noopener noreferrer"&gt;https://www.truckinfo.net/research/trucking-statistics&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Blog Sem Parar: &lt;a href="https://blog.sempararempresas.com.br/o-que-e-e-quais-sao-os-beneficios-da-roteirizacao-de-transporte/" rel="noopener noreferrer"&gt;https://blog.sempararempresas.com.br/o-que-e-e-quais-sao-os-beneficios-da-roteirizacao-de-transporte/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Google OR-Tools: &lt;a href="https://developers.google.com/optimization" rel="noopener noreferrer"&gt;https://developers.google.com/optimization&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Graphhopper : &lt;a href="https://www.graphhopper.com/blog/2017/09/18/route-optimization-explained/" rel="noopener noreferrer"&gt;https://www.graphhopper.com/blog/2017/09/18/route-optimization-explained/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O que é roteirização e como utilizar na sua operação:&lt;a href="https://www.lincros.com/blog/o-que-e-roteirizador" rel="noopener noreferrer"&gt;https://www.lincros.com/blog/o-que-e-roteirizador&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>datascience</category>
      <category>routing</category>
      <category>advanced</category>
    </item>
  </channel>
</rss>
