Bongani  Ngema

Bongani Ngema

1669959386

Install Sendmail on Ubuntu 22.04

How to install Sendmail on Ubuntu 22.04 and configure it for sending emails using a email server which routes or relays the mail delivery.

Sendmail is a opensource Mail Transfer Agent (MTA) which is used to route email using server or by using shell commands. You can also configure SMTP using Sendmail.

In this guide you are going to learn how to install and setup Sendmail on Ubuntu. Also you will setup SMTP and configure it with PHP.

Update Server Packages

SSH inside your server and update the packages to it’s latest version.

sudo apt update
sudo apt upgrade

Install Sendmail

Sendmail is available in the ubuntu repository, so you can directly install using apt install command.

sudo apt install sendmail

Configure Hostname

Edit the /etc/hosts file and add your hostname.

sudo nano /etc/hosts

On the line starting with 127.0.0.1, add the hostname to the end as it looks below. This should be on a single line.

127.0.0.1 localhost hostname

Configure SMTP

Create new directory inside /etc/mail for SMTP configurations.

sudo mkdir /etc/mail/authinfo

Setup correct permissions.

sudo chmod -R 700 /etc/mail/authinfo

Create a new file for your SMTP authentication inside the newly created directory.

cd /etc/mail/authinfo
sudo nano smtp-auth

Paste the following line and replace the email-address with your login email and password with your password.

AuthInfo: "U:root" "I:email-address" "P:password"

Hit CRTL + X followed by Y and ENTER to save and exit the file.

Create a hash database map for the above created authentication.

sudo makemap hash smtp-auth < smtp-auth

Configure SMTP

Navigate to the sendmail configuration directory and edit the sendmail.mc file.

cd /etc/mail
sudo nano sendmail.mc

Add the below configurations right after the MAILER _DEFINITIONS line.

Replace smtp-host with your SMTP hostname.

define(`SMART_HOST',`[smtp-host]')dnl
define(`RELAY_MAILER_ARGS', `TCP $h 587')dnl
define(`ESMTP_MAILER_ARGS', `TCP $h 587')dnl
define(`confAUTH_OPTIONS', `A p')dnl
TRUST_AUTH_MECH(`EXTERNAL DIGEST-MD5 CRAM-MD5 LOGIN PLAIN')dnl
define(`confAUTH_MECHANISMS', `EXTERNAL GSSAPI DIGEST-MD5 CRAM-MD5 LOGIN PLAIN')dnl
FEATURE(`authinfo',`hash -o /etc/mail/authinfo/smtp-auth.db')dnl

The configuration should look like the same as the below screenshot.

Now save the file and exit the editor.

Rebuild Sendmail Configuration

Once the configuration is done you need to rebuild the Sendmail configuration using the make command.

cd /etc/mail
make

Once the configuration is rebuilt you need to restart Sendmail

Restart Sendmail

Restart Sendmail using the following command.

sudo /etc/init.d/sendmail restart

Now you can send emails using SMTP.

Additional Configurations

Configuration with PHP

To use Sendmail with PHP you need to ad sendmail path in your php.ini file.

sudo nano /etc/php/version/fpm-or-apache2/php.ini

To the bottom of the file add the following.

sendmail_path= /usr/sbin/sendmail -t -i

Restart Apache or PHP-FPM for the changes to take effect.

sudo service apache2 restart

or

sudo service php8.1-fpm restart

Sendmail SMTP Configuration without Auth

Incase if you have whitelisted your server IP for SMTP and you can send emails without authentication you can follow the below method.

You don’t need to create the smtp-auth file that we created above.

You can directly edit the sendmail.mc file and make the following changes.

cd /etc/mail
sudo nano sendmail.mc

Add the below configurations to the last.

Replace smtp-host with your SMTP hostname.

define(`SMART_HOST',`smtp-host')dnl
define(`RELAY_MAILER', `esmtp')dnl
define(`RELAY_MAILER_ARGS', `TCP $h 587')dnl

Save the file, rebuild configuration and restart Sendmail.

cd /etc/mail
make
sudo /etc/init.d/sendmail restart

Prepare yourself for a role working as an Information Technology Professional with Linux operating system

Conclusion

Now you have learned how to install and configure Sendmail to relay using SMTP on Ubuntu 22.04.

Thanks for your time. If you face any problem or any feedback, please leave a comment below.

Original article source at: https://www.cloudbooklet.com/

#ubuntu #linux #send #emails 

Install Sendmail on Ubuntu 22.04
Dexter  Goodwin

Dexter Goodwin

1661168460

Ackee-lighthouse: Send Lighthouse Reports to Ackee

ackee-lighthouse

A script that runs continuously thanks to GitHub Actions and sends Lighthouse reports the Ackee.

🤗 Usage

1. Install dependencies

ackee-lighthouse dependents on …

Make sure to install and update all dependencies before you continue. The installation instructions for the individual dependencies can be found on the linked websites.

2. Create the configuration

Pull the project and configure ackee-lighthouse using environment variables or create a .env file in the root of the project to store all variables in one file.

Examples:

ACKEE_ENDPOINT=https://ackee.example.com/api
ACKEE_EVENT_ID=a26932b8-a088-4fc1-b723-c3ea5b9ba9e4
URL=https://a.example.com
ACKEE_ENDPOINT=https://ackee.example.com/api
ACKEE_EVENT_ID=a26932b8-a088-4fc1-b723-c3ea5b9ba9e4,6bad9a10-ed63-447b-b026-086b80da15d2
URL=https://a.example.com,https://b.example.com
AUDIT=speed-index.numericValue

3. Install ackee-lighthouse

Install all required dependencies.

yarn install

4. Run ackee-lighthouse

ackee-lighthouse will create a Lighthouse report for every URL specified in the environment. The AUDIT option must be a dot path that selects a single value from the Lighthouse report. It defaults to speed-index.numericValue, which will report the speed index as a numeric value (in milliseconds). ackee-lighthouse will send the selected value to the specified Ackee event.

Multiple URLs are handled so that the first URL uses the first event id, the second URL uses the second event id, and so on.

yarn start

Miscellaneous

Donate

I am working hard on continuously developing and maintaining Ackee. Please consider making a donation to keep the project going strong and me motivated.

Links

Download Details:

Author: Electerious
Source Code: https://github.com/electerious/ackee-lighthouse 
License: MIT license

#javascript #send #script 

Ackee-lighthouse: Send Lighthouse Reports to Ackee
高橋  花子

高橋 花子

1652355720

Djangoのクリーンコード原則

掃除はおそらくあなたの好きな娯楽活動ではありません、そしてそれは確かに私のものではありません😅。部屋を掃除する場合でも、コードを掃除する場合でも、おそらく良い時期ではないでしょう。しかし、どちらにも共通点があります。それは非常に重要です。

コンテンツ

  1. クリーンコードの原則のいくつか
  2. DjangoのKISS
  3. DjangoでDRY
  4. DjangoのYAGNI

1.クリーンコードの原則のいくつか

すでにご存知かもしれませんが、クリーンなコードはコンピューターやコンパイラーではなく、人間に関するものです。コンピューターの場合、構文が正しく、論理的に正しい限り、コードの記述方法は1ビット重要ではありません。しかし、人間はコンピューターではありません。同僚や他のプログラマーは、特にクリーンなコードを作成しなかった場合は、必ずしもコードを読み取ることができない場合があります。

最もよく知られているクリーンコードの原則のいくつかは次のとおりです。

  1. KISS(Keep It Simple(and)Stupid)
  2. DRY(繰り返さないでください)
  3. YAGNI(あなたはそれを必要としない)

次のパートでは、Djangoでこれらの原則の例を示します。

2.DjangoのKISS

KISS(Keep It Simple(and)Stupid)は基本的に、コードを短く、シンプルで、他の人が読みやすいものにするように指示しています。

-手動の代替手段ではなく、Djangoフォーム、シリアライザー、パーミッション、デコレーターを使用する

Djangoを学ぶとき、私がずっと前にしたように、おそらくDjangoフォーム、シリアライザー、および他の多くのことを学びました。しかし、時々、私はこれらのものを使用することの利点に疑問を抱くことがあります。フォーム用のHTMLコードを数行書くだけではいけませんか?または、シリアライザーやパーミッションを作成する代わりに、ビューにさらにコード行を記述しますか?はい、同じことをするためにそれを行うことができます。しかし、あなたはそれを行うことができるので、あなたがそれをすべきであるという意味ではありません。

まず、手動のHTMLフォームは安全ではありません。Djangoフォームを使用すると、クロスサイトリクエストフォージェリ保護としてCSRFトークンが使用されるため、フォームの安全性が高まります。これは自分で検索できますが、クリーンなコードの観点からは、手動のHTMLフォームには適していません。ここで比較を見てください:

Djangoフォームなし:

from django.shortcuts import render, redirect
from app.models import Object

def object_create(request):
    if request.POST:
        
        if request.POST.get("object_name") is None:
            # Handle bad data
            
        if request.POST.get("about_object") is None:
            # Handle bad data
        
	    object = Object.objects.create(
                object_name = request.POST.get("object_name"),
                about_object = request.POST.get("about_object"),
            )

	    return redirect("object:object_create_success", object.id)

	return render(request, 'objects/object_create.html', {
 		'form' : form,
	})

app / views.py

Djangoフォームの場合:

from django import forms
from app.models import Object

class ObjectCreationForm(forms.Form):
    object_name = forms.CharField(
        widget=forms.TextInput(attrs={'type' : 'text', 'placeholder' : 'Name of Object'})
    )
    about_object = forms.CharField(
        widget=forms.TextInput(attrs={'type' : 'text', 'placeholder' : 'About Object'})
    )

    def save(self, user):
        data = self.cleaned_data
        
        return Object.objects.create(
            object_name = data["object_name"],
            about_object = data["about_object"],
        )

app / forms.py

from django.shortcuts import render, redirect
from app.forms import ObjectCreationForm

def object_create(request):
    form = ObjectCreationForm(request.POST or None)

    if request.POST and form.is_valid():
        object = form.save(request.user)
        return redirect("object:object_create_success", object.id)

    return render(request, 'objects/object_create.html', {
 	'form' : form,
    })

app / views2.py

「ちょっと待ってください、Djangoフォームのコードは長くなりませんか?」と思うかもしれません。はい、forms.pyファイルを含めると長くなります。ただし、views.pyファイルのみを比較すると、Djangoフォームを使用したファイルは、Djangoフォームを使用しない場合よりもはるかに単純で読みやすいことがわかります。これは、最初のスニペットでコード(結合)が長くても、きちんと分離されているためです。これは、何が何をするのかをより簡単に推測できることを意味します。

これがKISSの原則の本質です。あなたは、あなたがより多くのコードを書くことになったり、それについてもっと考えなければならない場合でも、他の人のためにコードをシンプルで読みやすくする必要があります。これから取り除く最も重要なことは、他の人のためにシンプルで読みやすいコードを作成することです。

-関数ベースのビューではなく、クラスベースのビューを使用する

必要に応じて、関数ベースのビューの代わりにクラスベースのビューを使用します。これは、関数ベースのビューは対応するビューよりも柔軟性がありますが、クラスベースのビューは長くて冗長な関数/ビューで読みやすくなるためです。

ほとんどの人がクラスベースのビューについて知っている可能性があるため、これについては詳しく説明しませんが、Django REST Frameworkのクラスベースのビューについてもう少し詳しく説明している、Djangoでのリファクタリングに関する他のストーリーをここで確認できます。

3.DjangoでDRY

DRYまたはDon'tRepeat Yourselfは、それ自体を説明する原則です。コード内で繰り返すべきではありません。冗長性を減らすためにDjangoでできることは次のとおりです。

-ビューへのアクセスを制限するためにデコレータを使用する

これまでにデコレータを使用したことがない場合は、おそらく以前にビューにこれを書き込んだことがあります。

if request.user.is_authenticated:

また、1つのファイルに複数のビューがある場合は、次のようになります。

from django.http import HttpResponseRedirect
from django.urls import reverse

def a_view(request):
    if request.is_authenticated():
        # Do stuff
    else:
        return HttpResponseRedirect(reverse('users:login'))
    
def b_view(request):
    if request.is_authenticated():
        # Do stuff
    else:
        return HttpResponseRedirect(reverse('users:login'))

app2 / views.py

さて、コピーして貼り付けたり、何度も何度も繰り返したりしない、より良い方法があると言ったらどうでしょうか。デコレータの使い方は次のとおりです。

from django.http import HttpResponseRedirect
from django.urls import reverse


def login_required(view_func):
    def wrapper_func(request, *args, **kwargs):
	if request.user.is_authenticated:
            # If user is authenticated, let go to the view
	    return view_func(request, *args, **kwargs)
	else:
            # If user is not authenticated, redirect to login page
	    return HttpResponseRedirect(reverse('users:login'))
    return wrapper_func

app2/装飾者.py

from app2.decorators import login_required

@login_required
def a_view(request):
    # Do stuff
    
@login_required
def b_view(request):
    # Do stuff

app2 / views2.py

わお!かっこいいでしょ?また、デコレータで、必要なカスタムコードを記述できることもわかります。つまり、ビューへのアクセスを制限したり、どこかにリダイレクトしたりするためだけではありません。ユーザーがリファラーURLパスや想像できる他の多くのものなどのビューに移動する前に、ユーザーのセッションに保存することができます。空が限界!

-頻繁に使用するコードを別のヘルパー関数と別のファイルに配置する

これは、私たち全員にとって本当に簡単に実装できるもう1つの方法です。頻繁に使用するコードを別のヘルパー関数に抽出し、「utils.py」ファイルに配置します。

ヘルパー関数なしでメールを送信する例:

from django.shortcuts import render
from django.core.mail import send_mail
from django.conf import settings


def send_to_requester_views(request):
    email_to_list = [request.user.email]
    
    if settings.EMAIL_HOST_USER and settings.EMAIL_HOST_PASSWORD:
        send_mail(
	    "Subject of Email", # subject
	    "Hello there!", # message
	    settings.EMAIL_HOST_USER, # from
	    email_to_list, # to
	)
    return render(request, 'main/home.html')
        
    
 def send_to_all_views(request):
    email_to_list = User.objects.values_list('email', flat=True)
    
    if settings.EMAIL_HOST_USER and settings.EMAIL_HOST_PASSWORD:
        send_mail(
	    "Subject of Email Wohooo", # subject
	    "Hello ALL!", # message
	    settings.EMAIL_HOST_USER, # from
	    email_to_list, # to
	)
    return render(request, 'main/home.html')

app3 / views.py

ヘルパー関数を使用してメールを送信する例:

from django.core.mail import send_mail
from django.conf import settings


def send_email(email_subject, email_message, email_to_list):
    
    #send email only if host's email and password is set
    if settings.EMAIL_HOST_USER and settings.EMAIL_HOST_PASSWORD and len(email_to_list) > 0:
	send_mail(
	    email_subject, # subject
	    email_message, # message
	    settings.EMAIL_HOST_USER, # from
	    email_to_list, # to
	)

app3 / utils.py

from django.shortcuts import render
from app3.utils import send_email


def send_to_requester_views(request):
    email_to_list = [request.user.email]
    send_email("Subject of Email", "Hello there!", email_to_list)
    return render(request, 'main/home.html')
        
 def send_to_all_views(request):
    email_to_list = User.objects.values_list('email', flat=True)
    send_email("Subject of Email Wohooo", "Hello ALL!", email_to_list)
    return render(request, 'main/home.html')

app3 / views2.py

正直なところ、この違いは非常に明白であり、より複雑で複雑な関数にはさらに必要になります。

4.DjangoのYAGNI

YAGNIまたはあなたは必要ありませんそれは私たちに自分より先に進まないように告げる原則です。時々私とあなたの何人かは「未来」のためのコードを書くでしょう。たぶん、これかそれは後で必要になるので、今すぐ書いてみたほうがいいでしょうか?いいえ!ほとんどの場合、そのコードは必要ないので、クリーンなコードにとっては本当に悪い習慣です。

例として、前に説明したデコレータに戻ります。デコレータを作れることを知った後@login_required、「資格のある」ユーザーのために別のデコレータを作りたいと思います。ええと、私たちはこの「修飾された」ものを実際には実装していませんが、多分「将来」のために今それを書くでしょう。

from django.http import HttpResponseRedirect
from django.urls import reverse
from django.http import HttpResponseForbidden

def login_required(view_func):
    def wrapper_func(request, *args, **kwargs):
	if request.user.is_authenticated:
            # If user is authenticated, let go to the view
	    return view_func(request, *args, **kwargs)
	else:
            # If user is not authenticated, redirect to login page
	    return HttpResponseRedirect(reverse('users:login'))
	return wrapper_func


# NEW DECORATER FOR THE 'FUTURE'

def qualified_required(view_func):
    def wrapper_func(request, *args, **kwargs):
	if request.user.is_qualified:
            # If user is qualified, let go to the view
	    return view_func(request, *args, **kwargs)
	else:
            # If user is not qualified, redirect to login page
	    return HttpResponseForbidden()
	return wrapper_func

app4/装飾者.py

ええと…..それは終わりました。

2年後…

「この「修飾された」デコレータとは何ですか?」はい、おそらく忘れて使用したことはありません。それはおそらくそもそもそれを必要としなかったからです。したがって、これからのポイントは、プロジェクトに肥大化した厄介なコードベースが必要な場合を除いて、必要と見なされるまで機能やその他のコードを追加しないことです。 

ソース:https ://medium.com/@rico098098/clean-code-principles-in-django-b0563a4e12f5

#django #code #principles 

Djangoのクリーンコード原則
Diego  Elizondo

Diego Elizondo

1652355540

Principios De Código Limpio En Django

La limpieza probablemente no sea tu pasatiempo favorito, y ciertamente no es el mío 😅. Ya sea limpiando tu habitación o limpiando tu código, probablemente no sea un buen momento. Pero ambos tienen algo en común. Es muy importante.

Contenido

  1. Algunos de los principios de Clean Code
  2. Beso en Django
  3. SECO en Django
  4. YAGNI en Django

1. Algunos de los principios de Clean Code

Como ya sabrá, el código limpio no se trata de computadoras o compiladores, se trata de humanos. Para las computadoras, la forma en que escribes tu código no importa en lo más mínimo, siempre y cuando la sintaxis sea correcta y lógicamente correcta. Pero los humanos no somos computadoras. Es posible que sus compañeros de trabajo y otros programadores no necesariamente puedan leer su código, especialmente si no escribió un código limpio.

Algunos de los principios del Código Limpio más conocidos son:

  1. KISS (Mantenlo simple (y) estúpido)
  2. SECO (No te repitas)
  3. YAGNI (No lo vas a necesitar)

En las siguientes partes, intentaré mostrar ejemplos de estos principios en Django.

2. BESO en Django

KISS (Keep It Simple (and) Stupid) básicamente te está diciendo que mantengas tu código corto, simple y fácil de leer para los demás.

- Utilice formularios, serializadores, permisos y decoradores de Django en lugar de alternativas manuales

Al aprender Django, probablemente haya aprendido formularios, serializadores y muchas otras cosas de Django, como lo hice yo hace mucho tiempo. Pero a veces, me encuentro cuestionando el beneficio de usar estas cosas. ¿No podría simplemente escribir unas pocas líneas de códigos HTML para formularios? ¿O escribir más líneas de código en las vistas en lugar de hacer serializadores o permisos? Sí, puedes hacer exactamente eso para hacer lo mismo. Pero porque puedes hacerlo, no significa que DEBES hacerlo.

Lo primero es que los formularios HTML manuales no son seguros. Al usar formularios de Django, sus formularios estarán más seguros porque usa un token CSRF como protección contra la falsificación de solicitudes entre sitios. Puede buscar esto por su cuenta, pero desde la perspectiva del código limpio, tampoco es bueno para formularios HTML manuales. Mira la comparación aquí:

Sin formularios de Django:

from django.shortcuts import render, redirect
from app.models import Object

def object_create(request):
    if request.POST:
        
        if request.POST.get("object_name") is None:
            # Handle bad data
            
        if request.POST.get("about_object") is None:
            # Handle bad data
        
	    object = Object.objects.create(
                object_name = request.POST.get("object_name"),
                about_object = request.POST.get("about_object"),
            )

	    return redirect("object:object_create_success", object.id)

	return render(request, 'objects/object_create.html', {
 		'form' : form,
	})

aplicación/vistas.py

Con formularios de Django:

from django import forms
from app.models import Object

class ObjectCreationForm(forms.Form):
    object_name = forms.CharField(
        widget=forms.TextInput(attrs={'type' : 'text', 'placeholder' : 'Name of Object'})
    )
    about_object = forms.CharField(
        widget=forms.TextInput(attrs={'type' : 'text', 'placeholder' : 'About Object'})
    )

    def save(self, user):
        data = self.cleaned_data
        
        return Object.objects.create(
            object_name = data["object_name"],
            about_object = data["about_object"],
        )

app/formularios.py

from django.shortcuts import render, redirect
from app.forms import ObjectCreationForm

def object_create(request):
    form = ObjectCreationForm(request.POST or None)

    if request.POST and form.is_valid():
        object = form.save(request.user)
        return redirect("object:object_create_success", object.id)

    return render(request, 'objects/object_create.html', {
 	'form' : form,
    })

aplicación/views2.py

Puedes pensar, “espera un minuto, ¿no es más largo el código con los formularios de Django?”. Sí, es más largo si incluye el archivo Forms.py. Pero si compara solo el archivo views.py, verá que el que tiene formularios de Django será mucho más simple y fácil de leer que sin formularios de Django. Esto se debe a que incluso cuando el código (combinado) es más largo en el primer fragmento, se separa claramente. Esto significa que puede inferir qué se supone que debe hacer qué más fácilmente.

Esta es la esencia del principio KISS. Debe hacer que el código sea simple y fácil de leer para los demás, incluso si termina escribiendo más código o tiene que pensar más en él. Lo más importante que se debe sacar de esto es hacer un código simple y legible para otros.

- Usar vistas basadas en clases en lugar de vistas basadas en funciones

Utilice vistas basadas en clases en lugar de vistas basadas en funciones cuando sea necesario. Esto se debe a que, aunque las vistas basadas en funciones son más flexibles que sus contrapartes, las vistas basadas en clases serán más legibles en funciones/vistas largas y redundantes.

No iré muy lejos explicando esto, ya que la mayoría de la gente probablemente conoce las vistas basadas en clases, pero puede consultar mi otra historia sobre la refactorización en Django que va un poco más allá sobre las vistas basadas en clases en Django REST Framework aquí .

3. SECO en Django

DRY or Don't Repeat Yourself es un principio que se explica por sí solo. No deberías repetirte en tu código. Algunas cosas que puede hacer en Django para reducir la redundancia son:

- Use decoradores para restringir el acceso a las vistas

Si no ha usado decoradores antes, probablemente haya escrito esto en sus vistas antes:

if request.user.is_authenticated:

Y si tiene varias vistas en un archivo, podría verse así:

from django.http import HttpResponseRedirect
from django.urls import reverse

def a_view(request):
    if request.is_authenticated():
        # Do stuff
    else:
        return HttpResponseRedirect(reverse('users:login'))
    
def b_view(request):
    if request.is_authenticated():
        # Do stuff
    else:
        return HttpResponseRedirect(reverse('users:login'))

app2/views.py

Bueno, ¿y si te digo que hay una mejor manera que no implica copiar y pegar y repetirte una y otra vez? Así es como con los decoradores:

from django.http import HttpResponseRedirect
from django.urls import reverse


def login_required(view_func):
    def wrapper_func(request, *args, **kwargs):
	if request.user.is_authenticated:
            # If user is authenticated, let go to the view
	    return view_func(request, *args, **kwargs)
	else:
            # If user is not authenticated, redirect to login page
	    return HttpResponseRedirect(reverse('users:login'))
    return wrapper_func

app2/decoradores.py

from app2.decorators import login_required

@login_required
def a_view(request):
    # Do stuff
    
@login_required
def b_view(request):
    # Do stuff

app2/views2.py

¡Guau! ¿Guay, verdad? También puede ver que en el decorador, puede escribir cualquier código personalizado que desee. Por lo tanto, no es solo para restringir el acceso a las vistas o redirigirte a algún lugar. Puede guardar cosas en la sesión del usuario antes de que vaya a la vista, como rutas URL de referencia o muchas otras cosas que pueda imaginar. ¡El cielo es el limite!

- Coloque los códigos de uso frecuente para separar las funciones auxiliares y en un archivo separado

¡Este es otro en el que es realmente fácil de implementar para todos nosotros! Extraiga el código de uso frecuente en una función auxiliar separada y colóquelo en el archivo 'utils.py'.

Ejemplo de envío de correos electrónicos sin funciones auxiliares:

from django.shortcuts import render
from django.core.mail import send_mail
from django.conf import settings


def send_to_requester_views(request):
    email_to_list = [request.user.email]
    
    if settings.EMAIL_HOST_USER and settings.EMAIL_HOST_PASSWORD:
        send_mail(
	    "Subject of Email", # subject
	    "Hello there!", # message
	    settings.EMAIL_HOST_USER, # from
	    email_to_list, # to
	)
    return render(request, 'main/home.html')
        
    
 def send_to_all_views(request):
    email_to_list = User.objects.values_list('email', flat=True)
    
    if settings.EMAIL_HOST_USER and settings.EMAIL_HOST_PASSWORD:
        send_mail(
	    "Subject of Email Wohooo", # subject
	    "Hello ALL!", # message
	    settings.EMAIL_HOST_USER, # from
	    email_to_list, # to
	)
    return render(request, 'main/home.html')

app3/vistas.py

Ejemplo de envío de correos electrónicos con funciones auxiliares:

from django.core.mail import send_mail
from django.conf import settings


def send_email(email_subject, email_message, email_to_list):
    
    #send email only if host's email and password is set
    if settings.EMAIL_HOST_USER and settings.EMAIL_HOST_PASSWORD and len(email_to_list) > 0:
	send_mail(
	    email_subject, # subject
	    email_message, # message
	    settings.EMAIL_HOST_USER, # from
	    email_to_list, # to
	)

app3/utils.py

from django.shortcuts import render
from app3.utils import send_email


def send_to_requester_views(request):
    email_to_list = [request.user.email]
    send_email("Subject of Email", "Hello there!", email_to_list)
    return render(request, 'main/home.html')
        
 def send_to_all_views(request):
    email_to_list = User.objects.values_list('email', flat=True)
    send_email("Subject of Email Wohooo", "Hello ALL!", email_to_list)
    return render(request, 'main/home.html')

app3/vistas2.py

Para ser honesto, la diferencia es bastante marcada y sería mucho más necesaria para funciones más complicadas y complejas.

4. YAGNI en Django

YAGNI o You Aren't Gonna Need It es un principio que nos dice que no nos adelantemos. A veces yo y tal vez algunos de ustedes escribiríamos código para el 'futuro'. Tal vez necesitemos esto o aquello más adelante, así que mejor escribirlo ahora, ¿no? ¡No! Realmente es un mal hábito para el código limpio porque la mayoría de las veces, no necesitará ese código .

Como ejemplo, volveré a los decoradores que hemos discutido antes. Tal vez después de saber que podemos hacer @login_requireddecoradores, nos gustaría hacer otro para usuarios que estén 'cualificados'. Bueno, realmente no hemos implementado esta cosa 'calificada', pero tal vez lo escribamos ahora para el 'futuro'.

from django.http import HttpResponseRedirect
from django.urls import reverse
from django.http import HttpResponseForbidden

def login_required(view_func):
    def wrapper_func(request, *args, **kwargs):
	if request.user.is_authenticated:
            # If user is authenticated, let go to the view
	    return view_func(request, *args, **kwargs)
	else:
            # If user is not authenticated, redirect to login page
	    return HttpResponseRedirect(reverse('users:login'))
	return wrapper_func


# NEW DECORATER FOR THE 'FUTURE'

def qualified_required(view_func):
    def wrapper_func(request, *args, **kwargs):
	if request.user.is_qualified:
            # If user is qualified, let go to the view
	    return view_func(request, *args, **kwargs)
	else:
            # If user is not qualified, redirect to login page
	    return HttpResponseForbidden()
	return wrapper_func

app4/decoradores.py

Bueno... está hecho.

2 años después…

"¿Qué es eso de decorador 'cualificado'?" Sí, probablemente lo hayas olvidado y nunca lo hayas usado. Eso es porque probablemente no lo necesitabas en primer lugar. Por lo tanto, la conclusión de esto es que no debe agregar funcionalidad ni ningún otro código hasta que se considere necesario, a menos que desee una base de código inflada y desordenada para sus proyectos. 

Fuente: https://medium.com/@rico098098/clean-code-principles-in-django-b0563a4e12f5

#django #code #principles 

Principios De Código Limpio En Django
Elian  Harber

Elian Harber

1649926080

Guble: Websocket Based Messaging Server Written in Golang

Guble Messaging Server

Guble is a simple user-facing messaging and data replication server written in Go.

Overview

Guble is in an early state (release 0.4). It is already working well and is very useful, but the protocol, API and storage formats may still change (until reaching 0.7). If you intend to use guble, please get in contact with us.

The goal of guble is to be a simple and fast message bus for user interaction and replication of data between multiple devices:

  • Very easy consumption of messages with web and mobile clients
  • Fast realtime messaging, as well as playback of messages from a persistent commit log
  • Reliable and scalable over multiple nodes
  • User-aware semantics to easily support messaging scenarios between people using multiple devices
  • Batteries included: usable as front-facing server, without the need of a proxy layer
  • Self-contained: no mandatory dependencies to other services

Working Features (0.4)

  • Publishing and subscription of messages to topics and subtopics
  • Persistent message store with transparent live and offline fetching
  • WebSocket and REST APIs for message publishing
  • Commandline client and Go client library
  • Firebase Cloud Messaging (FCM) adapter: delivery of messages as FCM push notifications
  • Docker images for server and client
  • Simple Authentication and Access-Management
  • Clean shutdown
  • Improved logging using logrus and logstash formatter
  • Health-Check with Endpoint
  • Collection of Basic Metrics, with Endpoint
  • Added Postgresql as KV Backend
  • Load testing with 5000 messages per instance
  • Support for Apple Push Notification services (a new connector alongside Firebase)
  • Upgrade, cleanup, abstraction, documentation, and test coverage of the Firebase connector
  • GET list of subscribers / list of topics per subscriber (userID , deviceID)
  • Support for SMS-sending using Nexmo (a new connector alongside Firebase)

Throughput

Measured on an old notebook with i5-2520M, dual core and SSD. Message payload was 'Hello Word'. Load driver and server were set up on the same machine, so 50% of the cpu was allocated to the load driver.

  • End-2-End: Delivery of ~35.000 persistent messages per second
  • Fetching: Receive of ~70.000 persistent messages per second

During the tests, the memory consumption of the server was around ~25 MB.

Table of Contents

Roadmap

This is the current (and fast changing) roadmap and todo list:

Roadmap Release 0.5

  • Replication across multiple servers (in a Guble cluster)
  • Acknowledgement of message delivery for connectors
  • Storing the sequence-Id of topics in KV store, if we turn off persistence
  • Filtering of messages in guble server (e.g. sent by the REST client) according to URL parameters: UserID, DeviceID, Connector name
  • Updating README to show subscribe/unsubscribe/get/posting, health/metrics

Roadmap Release 0.6

  • Make notification messages optional by client configuration
  • Correct behaviour of receive command with maxCount on subtopics
  • Cancel of fetch in the message store and multiple concurrent fetch commands for the same topic
  • Configuration of different persistence strategies for topics
  • Delivery semantics: user must read on one device / deliver only to one device / notify if not connected, etc.
  • User-specific persistent subscriptions across all clients of the user
  • Client: (re-)setup of subscriptions after client reconnect
  • Message size limit configurable by the client with fetching by URL

Roadmap Release 0.7

  • HTTPS support in the service
  • Minimal example: chat application
  • Stable JavaScript client: https://github.com/smancke/guble-js
  • (TBD) Improved authentication and access-management
  • (TBD) Add Consul as KV Backend
  • (TBD) Index-based search of messages using GoLucene

Guble Docker Image

We are providing Docker images of the server and client for your convenience.

Start the Guble Server

There is an automated Docker build for the master at the Docker Hub. To start the server with Docker simply type:

docker run -p 8080:8080 smancke/guble

To see available configuration options:

docker run smancke/guble --help

All options can be supplied on the commandline or by a corresponding environment variable with the prefix GUBLE_. So to let guble be more verbose, you can either use:

docker run smancke/guble --log=info

or

docker run -e GUBLE_LOG=info smancke/guble

The Docker image has a volume mount point at /var/lib/guble, so if you want to bind-mount the persistent storage from your host you should use:

docker run -p 8080:8080 -v /host/storage/path:/var/lib/guble smancke/guble

Connecting with the Guble Client

The Docker image includes the guble commandline client guble-cli. You can execute it within a running guble container and connect to the server:

docker run -d --name guble smancke/guble
docker exec -it guble /usr/local/bin/guble-cli

Visit the guble-cli documentation for more details.

Build and Run

Since Go makes it very easy to build from source, you can compile guble using a single command. A prerequisite is having an installed Go environment and an empty directory:

sudo apt-get install golang
mkdir guble && cd guble
export GOPATH=`pwd`

Build and Start the Server

Build and start guble with the following commands (assuming that directory /var/lib/guble is already created with read-write rights for the current user):

go get github.com/smancke/guble
bin/guble --log=info

Configuration

CLI OptionEnv VariableValuesDefaultDescription
--envGUBLE_ENVdevelopment | integration | preproduction | productiondevelopmentName of the environment on which the application is running. Used mainly for logging
--health-endpointGUBLE_HEALTH_ENDPOINTresource/path/to/healthendpoint/admin/healthcheckThe health endpoint to be used by the HTTP server.Can be disabled by setting the value to ""
--httpGUBLE_HTTP_LISTENformat: [host]:port The address to for the HTTP server to listen on
--kvsGUBLE_KVSmemory | file | postgresfileThe storage backend for the key-value store to use
--logGUBLE_LOGpanic | fatal | error | warn | info | debugerrorThe log level in which the process logs
--metrics-endpointGUBLE_METRICS_ENDPOINTresource/path/to/metricsendpoint/admin/metricsThe metrics endpoint to be used by the HTTP server.Can be disabled by setting the value to ""
--msGUBLE_MSmemory | filefileThe message storage backend
--profileGUBLE_PROFILEcpu | mem | block The profiler to be used
--storage-pathGUBLE_STORAGE_PATHpath/to/storage/var/lib/gubleThe path for storing messages and key-value data like subscriptions if defined.The path must exists!

APNS

CLI OptionEnv VariableValuesDefaultDescription
--apnsGUBLE_APNStrue | falsefalseEnable the APNS module in general as well as the connector to the development endpoint
--apns-productionGUBLE_APNS_PRODUCTIONtrue | falsefalseEnables the connector to the apns production endpoint, requires the apns option to be set
--apns-cert-fileGUBLE_APNS_CERT_FILEpath/to/cert/file The APNS certificate file name, use this as an alternative to the certificate bytes option
--apns-cert-bytesGUBLE_APNS_CERT_BYTEScert-bytes-as-hex-string The APNS certificate bytes, use this as an alternative to the certificate file option
--apns-cert-passwordGUBLE_APNS_CERT_PASSWORDpassword The APNS certificate password
--apns-app-topicGUBLE_APNS_APP_TOPICtopic The APNS topic (as used by the mobile application)
--apns-prefixGUBLE_APNS_PREFIXprefix/apns/The APNS prefix / endpoint
--apns-workersGUBLE_APNS_WORKERSnumber of workersNumber of CPUsThe number of workers handling traffic with APNS (default: number of CPUs)

SMS

CLI OptionEnv VariableValuesDefaultDescription
smsGUBLE_SMStrue | falsefalseEnable the SMS gateway
sms_api_keyGUBLE_SMS_API_KEYapi key The Nexmo API Key for Sending sms
sms_api_secretGUBLE_SMS_API_SECRETapi secret The Nexmo API Secret for Sending sms
sms_topicGUBLE_SMS_TOPICtopic/smsThe topic for sms route
sms_workersGUBLE_SMS_WORKERSnumber of workersNumber of CPUsThe number of workers handling traffic with Nexmo sms endpoint

FCM

CLI OptionEnv VariableValuesDefaultDescription
`--fcmGUBLE_FCM`true | falsefalseEnable the Google Firebase Cloud Messaging connector
--fcm-api-keyGUBLE_FCM_API_KEYapi key The Google API Key for Google Firebase Cloud Messaging
--fcm-workersGUBLE_FCM_WORKERSnumber of workersNumber of CPUsThe number of workers handling traffic with Firebase Cloud Messaging
--fcm-endpointGUBLE_FCM_ENDPOINTformat: url-schemahttps://fcm.googleapis.com/fcm/sendThe Google Firebase Cloud Messaging endpoint
--fcm-prefixGUBLE_FCM_PREFIXprefix/fcm/The FCM prefix / endpoint

Postgres

CLI OptionEnv VariableValuesDefaultDescription
--pg-hostGUBLE_PG_HOSThostnamelocalhostThe PostgreSQL hostname
--pg-portGUBLE_PG_PORTport5432The PostgreSQL port
--pg-userGUBLE_PG_USERusergubleThe PostgreSQL user
--pg-passwordGUBLE_PG_PASSWORDpasswordgubleThe PostgreSQL password
--pg-dbnameGUBLE_PG_DBNAMEdatabasegubleThe PostgreSQL database name

Run All Tests

go get -t github.com/smancke/guble/...
go test github.com/smancke/guble/...

Clients

The following clients are available:

Protocol Reference

REST API

Currently there is a minimalistic REST API, just for publishing messages.

POST /api/message/<topic>

URL parameters:

  • userId: The PublisherUserId
  • messageId: The PublisherMessageId

Headers

You can set fields in the header JSON of the message by providing the corresponding HTTP headers with the prefix X-Guble-.

Curl example with the resulting message:

curl -X POST -H "x-Guble-Key: Value" --data Hello 'http://127.0.0.1:8080/api/message/foo?userId=marvin&messageId=42'

Results in:

16,/foo,marvin,VoAdxGO3DBEn8vv8,42,1451236804
{"Key":"Value"}
Hello

WebSocket Protocol

The communication with the guble server is done by ordinary WebSockets, using a binary encoding.

Message Format

All payload messages sent from the server to the client are using the following format:

<path:string>,<sequenceId:int64>,<publisherUserId:string>,<publisherApplicationId:string>,<publisherMessageId:string>,<messagePublishingTime:unix-timestamp>\n
[<application headers json>]\n
<body>

example 1:
/foo/bar,42,user01,phone1,id123,1420110000
{"Content-Type": "text/plain", "Correlation-Id": "7sdks723ksgqn"}
Hello World

example 2:
/foo/bar,42,user01,54sdcj8sd7,id123,1420110000

anyByteData
  • All text formats are assumed to be UTF-8 encoded.
  • Message sequenceIds are int64, and distinct within a topic. The message sequenceIds are strictly monotonically increasing depending on the message age, but there is no guarantee for the right order while transmitting.

Client Commands

The client can send the following commands.

Send

Publish a message to a topic:

> <path> [<publisherMessageId>]\n
[<header>\n]..
\n
<body>

example:
> /foo

Hello World

Subscribe/Receive

Receive messages from a path (e.g. a topic or subtopic). This command can be used to subscribe for incoming messages on a topic, as well as for replaying the message history.

+ <path> [<startId>[,<maxCount>]]
  • path: the topic to receive the messages from
  • startId: the message id to start the replay ** If no startId is given, only future messages will be received (simple subscribe). ** If the startId is negative, it is interpreted as relative count of last messages in the history.
  • maxCount: the maximum number of messages to replay

Note: Currently, the fetching of stored messages does not recognize subtopics.

Examples:

+ /foo         # Subscribe to all future messages matching /foo
+ /foo/bar     # Subscribe to all future messages matching /foo/bar

+ /foo 0       # Receive all message from the topic and subscribe for further incoming messages.

+ /foo 42      # Receive all message with message ids >= 42
               # from the topic and subscribe for further incoming messages.

+ /foo 0 20    # Receive the first (oldest) 20 messages within the topic and stop.
               # (If the topic has less messages, it will stop after receiving all existing ones.)

+ /foo -20     # Receive the last (newest) 20 messages from the topic and then
               # subscribe for further incoming messages.

+ /foo -20 20  # Receive the last (newest) 20 messages within the topic and stop.
               # (If the topic has less messages, it will stop after receiving all existing ones.)

Unsubscribe/Cancel

Cancel further receiving of messages from a path (e.g. a topic or subtopic).

- <path>

example:
- /foo
- /foo/bar

Server Status Messages

The server sends status messages to the client. All positive status messages start with >. Status messages reporting an error start with !. Status messages are in the following format.

'#'<msgType> <Explanation text>\n
<json data>

Connection Message

#ok-connected You are connected to the server.\n
{"ApplicationId": "the app id", "UserId": "the user id", "Time": "the server time as unix timestamp "}

Example:

#connected You are connected to the server.
{"ApplicationId": "phone1", "UserId": "user01", "Time": "1420110000"}

Send Success Notification

This notification confirms, that the messaging system has successfully received the message and now starts transmitting it to the subscribers:

#send <publisherMessageId>
{"sequenceId": "sequence id", "path": "/foo", "publisherMessageId": "publishers message id", "messagePublishingTime": "unix-timestamp"}

Receive Success Notification

Depending on the type of + (receive) command, up to three different notification messages will be sent back. Be aware, that a server may send more receive notifications that you would have expected in first place, e.g. when:

  • Additional messages are stored, while the first fetching is in progress
  • The server decides to meanwhile stop the online subscription and change to fetching, because your client is too slow to read all incoming messages.

When the fetch operation starts:

#fetch-start <path> <count>
  • path: the topic path
  • count: the number of messages that will be returned

When the fetch operation is done:

#fetch-done <path>
  • path: the topic path

When the subscription to new messages was taken:

#subscribed-to <path>
  • path: the topic path

Unsubscribe Success Notification

An unsubscribe/cancel operation is confirmed by the following notification:

#canceled <path>

Send Error Notification

This message indicates, that the message could not be delivered.

!error-send <publisherMessageId> <error text>
{"sequenceId": "sequence id", "path": "/foo", "publisherMessageId": "publishers message id", "messagePublishingTime": "unix-timestamp"}

Bad Request

This notification has the same meaning as the http 400 Bad Request.

!error-bad-request unknown command 'sdcsd'

Internal Server Error

This notification has the same meaning as the http 500 Internal Server Error.

!error-server-internal this computing node has problems

Topics

Messages can be hierarchically routed by topics, so they are represented by a path, separated by /. The server takes care, that a message only gets delivered once, even if it is matched by multiple subscription paths.

Subtopics

The path delimiter gives the semantic of subtopics. With this, a subscription to a parent topic (e.g. /foo) also results in receiving all messages of the subtopics (e.g. /foo/bar).

Author: Smancke
Source Code: https://github.com/smancke/guble 
License: MIT License

#go #golang #server 

Guble: Websocket Based Messaging Server Written in Golang
Noah Saunders

Noah Saunders

1646363857

A Beginner’s Guide to Quantitative Trading with Python

Technology has become an asset in finance. Financial institutions are now evolving into technology companies rather than just staying occupied with the financial aspects of the field.

Mathematical Algorithms bring about innovation and speed. They can help us gain a competitive advantage in the market.

The speed and frequency of financial transactions, together with the large data volumes, has drawn a lot of attention towards technology from all the big financial institutions.

Algorithmic or Quantitative trading is the process of designing and developing trading strategies based on mathematical and statistical analyses. It is an immensely sophisticated area of finance.

This tutorial serves as the beginner’s guide to quantitative trading with Python. You’ll find this post very helpful if you are:

  1. A student or someone aiming to become a quantitative analyst (quant) at a fund or bank.
  2. Someone who is planning to start their own quantitative trading business.

We’ll go over the following topics in this post:

  • Basics of stocks and trading
  • Extracting data from Quandl API
  • Exploratory data analysis on stock pricing data
  • Moving averages
  • Formulating a trading strategy with Python
  • Visualizing the performance of the strategy

Before we deep dive into the details and dynamics of stock pricing data, we must first understand the basics of finance. If you are someone who is familiar with finance and how trading works, you can skip this section and click here to go to the next one.

What Are Stocks? What is Stock Trading?

Stocks

A stock is a representation of a share in the ownership of a corporation, which is issued at a certain amount. It is a type of financial security that establishes your claim on a company’s assets and performance.

An organization or company issues stocks to raise more funds/capital in order to scale and engage in more projects. These stocks are then publicly available and are sold and bought.

Stock Trading and Trading Strategy

The process of buying and selling existing and previously issued stocks is called stock trading. There is a price at which a stock can be bought and sold, and this keeps on fluctuating depending upon the demand and the supply in the share market.

Depending on the company’s performance and actions, stock prices may move up and down, but the stock price movement is not limited to the company’s performance.

Traders pay money in return for ownership within a company, hoping to make some profitable trades and sell the stocks at a higher price.

Another important technique that traders follow is short selling . This involves  borrowing shares and immediately selling them in the hope of buying them up later at a lower price, returning them to the lender, and making the margin.

So, most traders follow a plan and model to trade. This is known as a trading strategy.

Quantitative traders at hedge funds and investment banks design and develop these trading strategies and frameworks to test them. It requires profound programming expertise and an understanding of the languages needed to build your own strategy.

Python is one of the most popular programming languages used, among the likes of C++, Java, R, and MATLAB. It is being adopted widely across all domains, especially in data science, because of its easy syntax, huge community, and third-party support.

You’ll need familiarity with Python and statistics in order to make the most of this tutorial. Make sure to brush up on your Python and check out the fundamentals of statistics.

Extracting data from the Quandl API

In order to extract stock pricing data, we’ll be using the Quandl API. But before that, let’s set up the work environment. Here’s how:

  1. In your terminal, create a new directory for the project (name it however you want):
mkdir <directory_name>
  1. Make sure you have Python 3 and virtualenv installed on your machine.
  2. Create a new Python 3 virtualenv using virtualenv <env_name> and activate it using source <env_name>/bin/activate.
  3. Now, install jupyter-notebook using pip, and type in pip install jupyter-notebook in the terminal.
  4. Similarly, install the pandas, quandl, and numpy packages.
  5. Run your jupyter-notebook from the terminal.

Now, your notebook should be running on localhost like the screenshot below:

1-1

You can create your first notebook by clicking on the New dropdown on the right. Make sure you have created an account on Quandl. Follow the steps mentioned here to create your API key.

Once you’re all set, let’s dive right in:

# importing required packages
import pandas as pd
import quandl as q

Pandas is going to be the most rigorously used package in this tutorial as we’ll be doing a lot of data manipulation and plotting.

After the packages are imported, we will make requests to the Quandl API by using the Quandl package:

# set the API key
q.ApiConfig.api_key = "<API key>”
#send a get request to query Microsoft's end of day stock prices from 1st #Jan, 2010 to 1st Jan, 2019

msft_data = q.get("EOD/MSFT", start_date="2010-01-01", end_date="2019-01-01")
# look at the first 5 rows of the dataframe

msft_data.head()

2-3

Here we have Microsoft’s EOD stock pricing data for the last 9 years. All you had to do was call the get method from the Quandl package and supply the stock symbol, MSFT, and the timeframe for the data you need.

This was really simple, right? Let’s move ahead to understand and explore this data further.

Exploratory Data Analysis on Stock Pricing Data

With the data in our hands, the first thing we should do is understand what it represents and what kind of information it encapsulates.

Printing the DataFrame’s info, we can see all that it contains:

3-1

As seen in the screenshot above, the DataFrame contains DatetimeIndex, which means we’re dealing with time-series data.

An index can be thought of as a data structure that helps us modify or reference the data. Time-series data is a sequence of snapshots of prices taken at consecutive, equally spaced intervals of time.

In trading, EOD stock pricing data captures the movement of certain parameters about a stock, such as the stock price, over a specified period of time with data points recorded at regular intervals.

Important Terminology

Looking at other columns, let’s try to understand what each column represents:

  • Open/Close — Captures the opening/closing price of the stock
  • Adj_Open/Adj_Close — An adjusted opening/closing price is a stock’s price on any given day of trading that has been revised to include any dividend distributions, stock splits, and other corporate actions that occurred at any time before the next day’s open.
  • Volume — It records the number of shares that are being traded on any given day of trading.
  • High/Low — It tracks the highest and the lowest price of the stock during a particular day of trading.

These are the important columns that we will focus on at this point in time.

We can learn about the summary statistics of the data, which shows us the number of rows, mean, max, standard deviations, and so on. Try running the following line of code in the Ipython cell:

msft_data.describe()

4-1

resample()

Pandas’ resample() method is used to facilitate control and flexibility on the frequency conversion of the time series data. We can specify the time intervals to resample the data to monthly, quarterly, or yearly, and perform the required operation over it.

msft_data.resample('M').mean()

5-1

This is an interesting way to analyze stock performance in different timeframes.

Calculating returns

A financial return is simply the money made or lost on an investment. A return can be expressed nominally as the change in the amount of an investment over time. It can be calculated as the percentage derived from the ratio of profit to investment.

We have the pct_change() at our disposal for this purpose. Here is how you can calculate returns:

# Import numpy package
import numpy as np
# assign `Adj Close` to `daily_close`
daily_close = msft_data[['Adj_Close']]
# returns as fractional change
daily_return = daily_close.pct_change()
# replacing NA values with 0

daily_return.fillna(0, inplace=True)
print(daily_return)

This will print the returns that the stock has been generating on a daily basis. Multiplying the number by 100 will give you the percentage change.

The formula used in pct_change() is:

Return = {(Price at t) — (Price at t-1)} / {Price at t-1}

Now, to calculate monthly returns, all you need to do is:

mdata = msft_data.resample('M').apply(lambda x: x[-1])

monthly_return = mdata.pct_change()

After resampling the data to months (for business days), we can get the last day of trading in the month using the apply() function.

apply() takes in a function and applies it to each and every row of the Pandas series. The lambda function is an anonymous function in Python which can be defined without a name, and only takes expressions in the following format:

Lambda: expression

For example, lambda x: x * 2 is a lambda function. Here, x is the argument and x * 2 is the expression that gets evaluated and returned.

Moving Averages in Trading

The concept of moving averages is going to build the base for our momentum-based trading strategy.

In finance, analysts often have to evaluate statistical metrics continually over a sliding window of time, which is called moving window calculations.

Let’s see how we can calculate the rolling mean over a window of 50 days, and slide the window by 1 day.

rolling()

This is the magical function which does the tricks for us:

# assigning adjusted closing prices to 

adj_pricesadj_price = msft_data['Adj_Close']
# calculate the moving average
mav = adj_price.rolling(window=50).mean()
# print the resultprint(mav[-10:])

6-1

You’ll see the rolling mean over a window of 50 days (approx. 2 months). Moving averages help smooth out any fluctuations or spikes in the data, and give you a smoother curve for the performance of the company.

We can plot and see the difference:

# import the matplotlib package to see the plot

import matplotlib.pyplot as plt

adj_price.plot()

7-1

You can now plot the rolling mean():

mav.plot()

8-1

And you can see the difference for yourself, how the spikes in the data are consumed to give a general sentiment around the performance of the stock.

Formulating a Trading Strategy

Here comes the final and most interesting part: designing and making the trading strategy. This will be a step-by-step guide to developing a momentum-based Simple Moving Average Crossover (SMAC) strategy.

Momentum-based strategies are based on a technical indicator that capitalizes on the continuance of the market trend. We purchase securities that show an upwards trend and short-sell securities which show a downward trend.

The SMAC strategy is a well-known schematic momentum strategy. It is a long-only strategy. Momentum, here, is the total return of stock including the dividends over the last n months. This period of n months is called the lookback period.

There are 3 main types of lookback periods: short term, intermediate-term, and long term. We need to define 2 different lookback periods of a particular time series.

A buy signal is generated when the shorter lookback rolling mean (or moving average) overshoots the longer lookback moving average. A sell signal occurs when the shorter lookback moving average dips below the longer moving average.

Now, let’s see how the code for this strategy will look:

# step1: initialize the short and long lookback periods

short_lb = 50long_lb = 120
# step2: initialize a new DataFrame called signal_df with a signal column

signal_df = pd.DataFrame(index=msft_data.index)signal_df['signal'] = 0.0
# step3: create a short simple moving average over the short lookback period
signal_df['short_mav'] = msft_data['Adj_Close'].rolling(window=short_lb,                                     min_periods=1, center=False).mean()
# step4: create long simple moving average over the long lookback period

signal_df['long_mav'] = msft_data['Adj_Close'].rolling(window=long_lb, min_periods=1, center=False).mean()
# step5: generate the signals based on the conditional statement

signal_df['signal'][short_lb:] = np.where(signal_df['short_mav'][short_lb:] > signal_df['long_mav'][short_lb:], 1.0, 0.0)   
# step6: create the trading orders based on the positions column

signal_df['positions'] = signal_df['signal'].diff()signal_df[signal_df['positions'] == -1.0]

Let’s see what’s happening here. We have created 2 lookback periods. The short lookback period short_lb is 50 days, and the longer lookback period for the long moving average is defined as a long_lb of 120 days.

We have created a new DataFrame which is designed to capture the signals. These signals are being generated whenever the short moving average crosses the long moving average using the np.where. It assigns 1.0 for true and 0.0 if the condition comes out to be false.

The positions columns in the DataFrame tells us if there is a buy signal or a sell signal, or to stay put. We're basically calculating the difference in the signals column from the previous row using diff.

And there we have our strategy implemented in just 6 steps using Pandas. Easy, wasn't it?

Now, let’s try to visualize this using Matplotlib. All we need to do is initialize a plot figure, add the adjusted closing prices, short, and long moving averages to the plot, and then plot the buy and sell signals using the positions column in the signal_df above:

# initialize the plot using plt
fig = plt.figure()
# Add a subplot and label for y-axis

plt1 = fig.add_subplot(111,  ylabel='Price in $')
msft_data['Adj_Close'].plot(ax=plt1, color='r', lw=2.)
# plot the short and long lookback moving averages
signal_df[['short_mav', 'long_mav']].plot(ax=plt1, lw=2., figsize=(12,8))
# plotting the sell signals

plt1.plot(signal_df.loc[signal_df.positions == -1.0].index,                         signal_df.short_mav[signal_df.positions == -1.0],'v',                     markersize=10, color='k')
# plotting the buy signals

plt1.plot(signal_df.loc[signal_df.positions == 1.0].index,          signal_df.short_mav[signal_df.positions == 1.0],         '^', markersize=10, color='m')         # Show the plotplt.show()

Running the above cell in the Jupyter notebook would yield a plot like the one below:

9-1

Now, you can clearly see that whenever the blue line (short moving average) goes up and beyond the orange line (long moving average), there is a pink upward marker indicating a buy signal.

A sell signal is denoted by a black downward marker where there’s a fall of the short_mav below long_mav.

Visualize the Performance of the Strategy on Quantopian

Quantopian is a Zipline-powered platform that has manifold use cases. You can write your own algorithms, access free data, backtest your strategy, contribute to the community, and collaborate with Quantopian if you need capital.

We have written an algorithm to backtest our SMA strategy, and here are the results:

10-1

Here is an explanation of the above metrics:

  • Total return: The total percentage return of the portfolio from the start to the end of the backtest.
  • Specific return: The difference between the portfolio’s total returns and common returns.
  • Common return: Returns that are attributable to common risk factors. There are 11 sector and 5 style risk factors that make up these returns. The Sector Exposure and Style Exposure charts in the Risk section provide more detail on these factors.
  • Sharpe: The 6-month rolling Sharpe ratio. It is a measure of risk-adjusted investment. It is calculated by dividing the portfolio’s excess returns over the risk-free rate by the portfolio’s standard deviation.
  • Max Drawdown: The largest drop of all the peak-to-trough movement in the portfolio’s history.
  • Volatility: Standard deviation of the portfolio’s returns.

Original article source at https://www.freecodecamp.org

#python

 

A Beginner’s Guide to Quantitative Trading with Python