Qlitre's Blog

2021.12.28 Django

Python DjangoとMDBで作る株取引ノート ①プロジェクトの初期設定

Python DjangoとMDBで作る株取引ノートシリーズの最初の記事です。

今回はCSSフレームワークとして、MDB(Material Design for Bootstrap)を使用していきます。
いま流行りのMaterial Designが簡単に実装できるBootstrapをベースにしたフレームワークです。

プロジェクトの開始、初期設定


まずはプロジェクトを開始します。
適当なディレクトリにプロジェクトフォルダであるtradenoteを作成し、requirements.txtを作成します。

# requirements.txt
django~=3.2.1


必要なライブラリは適宜追加していきます。
次にプロジェクトフォルダ内に仮想環境を作成し、djangoを読み込みます。

cd tradenote
python -m venv myvenv
myvenv\scripts\activate
pip install -r requirements.txt


Djangoプロジェクトをスタートさせます。
最後の.を忘れないようにしましょう。

django-admin startproject project .


次に実際に株取引を記録するノートアプリを作成します。

python manage.py startapp note


# project/settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'note.apps.NoteConfig', # 追加
]

...

LANGUAGE_CODE = 'ja' # 変更

TIME_ZONE = 'Asia/Tokyo' # 変更

...

STATIC_URL = '/static/'
STATIC_ROOT = BASE_DIR / 'static'  # 追加


とりあえずここまででいいでしょう。
次にコマンドラインから一旦モデルをmigrateしておきます。

python manage.py migrate
>>>
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  ....
  Applying sessions.0001_initial... OK


superuserを作っておきます。

python manage.py createsuperuser


プロジェクト内のurls.pyを下記のようにします。

# project/urls.py
from django.contrib import admin
from django.urls import path
from django.conf.urls import include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('note.urls')),
]


noteアプリ内にurls.pyを作成します。

# note/urls.py

from django.urls import path
from . import views

app_name = 'note'

urlpatterns = [
]


とりあえず内容は空にしておき、後で追加していきます。

モデルの作成

次に実際に株取引を記録するモデルを作っていきます。
noteアプリ内のmodels.pyを以下のようにします。

# note/models.py

from django.db import models

# bootstrapのテーマカラー
COLOR_CHOICES = (('primary', 'primary'),
                 ('secondary', 'secondary'),
                 ('success', 'success'),
                 ('info', 'info'),
                 ('warning', 'warning'),
                 ('danger', 'danger'),
                 ('light', 'light'),
                 ('dark', 'dark'))


class Status(models.Model):
    """保有中、終了などのステータス"""
    name = models.CharField(max_length=32)
    color = models.CharField(verbose_name='テーマカラー', choices=COLOR_CHOICES, max_length=32, null=True, blank=True)

    def __str__(self):
        return self.name


class Result(models.Model):
    """勝敗結果"""
    name = models.CharField(max_length=12)
    color = models.CharField(verbose_name='テーマカラー', choices=COLOR_CHOICES, max_length=32, null=True, blank=True)

    def __str__(self):
        return self.name


class Transaction(models.Model):
    """取引モデル"""
    ticker_code = models.CharField(verbose_name='銘柄コード', max_length=12)
    ticker_name = models.CharField(verbose_name='銘柄名', max_length=32)
    status = models.ForeignKey(to=Status, verbose_name='ステータス', blank=True, null=True, on_delete=models.PROTECT)
    date_entry = models.DateField(verbose_name='エントリー日', blank=True, null=True)
    date_close = models.DateField(verbose_name='手仕舞い日', blank=True, null=True)
    result = models.ForeignKey(to=Result, verbose_name='勝敗結果', blank=True, null=True, on_delete=models.PROTECT)
    reason = models.TextField(verbose_name='エントリー理由', null=True, blank=True)
    memo = models.TextField(verbose_name='メモ', default='', null=True, blank=True)
    benefit = models.BigIntegerField(verbose_name='損益', null=True, blank=True)

    def __str__(self):
        return f'#{self.pk} {self.ticker_name}'


class History(models.Model):
    """売買履歴"""
    date_trade = models.DateField(verbose_name='売買日')
    trading_category = models.CharField(verbose_name='売買区分',
                                        max_length=12,
                                        choices=(('Buy', 'Buy'),
                                                 ('Sell', 'Sell'),
                                                 ('Dividend', 'Dividend')))
    target = models.ForeignKey(to=Transaction, verbose_name='対象取引', on_delete=models.PROTECT)
    price = models.FloatField(verbose_name='単価')
    quantity = models.IntegerField(verbose_name='数量')
    commission = models.IntegerField(verbose_name='手数料', null=True, blank=True)
    amount = models.BigIntegerField(verbose_name='受渡金額')


まず最初のCOLOR_CHOICE変数ですが、bootstrapのテーマカラーを定義しています。
保有中、クローズなどのステータスを定義するStatusモデルと、勝敗結果を管理するResultモデルから参照するようにしています。
後々にページをデザインする際に、カテゴリによって色分けができるので便利です。

Transactionモデルは実際の取引を管理するモデルです。
ここで「いつエントリーして、利益はどうだったのか」などの情報を管理するようにしていきます。
理由やメモのフィールドを加えることで、その取引中にあたって考えたことや、反省点などを振り返られるようにする、という感じです。

HistoryモデルはTransactionモデルの下の階層で、実際の売買履歴を管理します。
購入(Buy)と売却(Sell)と配当(Dividend)でお金の出入りを記入できるようにします。

まず取引のマスターとしてTransactionを登録していき、それに紐づく形でHistoryを登録していくようなイメージです。

ここで再びmigrateをしておきましょう。

python manage.py makemigrations
>>>
Migrations for 'note':
  note\migrations\0001_initial.py
    - Create model Result
    - Create model Status
    - Create model Transaction
    - Create model History

python manage.py migrate
>>>
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, note, sessions
Running migrations:
  Applying note.0001_initial... OK


admin.pyの編集

次にnoteアプリ内のadmin.pyを以下のようにします。

# note/admin.py

from django.contrib import admin
from .models import Result, Transaction, History, Status


class StatusAdmin(admin.ModelAdmin):
    list_display = ['name', 'color']


class ResultAdmin(admin.ModelAdmin):
    list_display = ['name', 'color']


class TransactionAdmin(admin.ModelAdmin):
    search_fields = ('ticker_code', 'ticker_name', 'memo')
    list_display = ['ticker_code', 'ticker_name', 'date_entry', 'date_close', 'benefit']


class HistoryAdmin(admin.ModelAdmin):
    list_display = ['target', 'date_trade', 'trading_category', 'price', 'amount']


admin.site.register(Status, StatusAdmin)
admin.site.register(Result, ResultAdmin)
admin.site.register(Transaction, TransactionAdmin)
admin.site.register(History, HistoryAdmin)



runserverしてadminサイトにログインしてみます。

python manage.py runserver




このようにモデルが表示されていればとりあえず大丈夫です。

StatusとResultはこのタイミングで簡単に追加しておきましょう。
Statusに手仕舞いしていることを示すCloseと保有中を示すHoldingを加えて、
Resultに勝敗を示すWinLoseを登録します。

テーマカラーは以下の写真のようにしました。





次回以降に実際のページを作りこんでいきます。