From 2cbc82a535bb35a7e97546fe8215d895e45ba4ee Mon Sep 17 00:00:00 2001 From: Reckless_Satoshi Date: Sun, 16 Jan 2022 08:06:53 -0800 Subject: [PATCH] Convert cached currency to relation children of order --- api/admin.py | 10 +++++----- api/logics.py | 8 ++++---- api/models.py | 43 +++++++++++++++++++++++++++++-------------- api/tasks.py | 11 ++++++----- api/views.py | 4 ++-- 5 files changed, 46 insertions(+), 30 deletions(-) diff --git a/api/admin.py b/api/admin.py index da92dcc5..2b485053 100644 --- a/api/admin.py +++ b/api/admin.py @@ -2,7 +2,7 @@ from django.contrib import admin from django_admin_relation_links import AdminChangeLinksMixin from django.contrib.auth.models import Group, User from django.contrib.auth.admin import UserAdmin -from .models import Order, LNPayment, Profile, MarketTick, CachedExchangeRate +from .models import Order, LNPayment, Profile, MarketTick, Currency admin.site.unregister(Group) admin.site.unregister(User) @@ -24,9 +24,9 @@ class EUserAdmin(UserAdmin): @admin.register(Order) class OrderAdmin(AdminChangeLinksMixin, admin.ModelAdmin): - list_display = ('id','type','maker_link','taker_link','status','amount','currency','t0_satoshis','is_disputed','is_fiat_sent','created_at','expires_at', 'buyer_invoice_link','maker_bond_link','taker_bond_link','trade_escrow_link') + list_display = ('id','type','maker_link','taker_link','status','amount','currency_link','t0_satoshis','is_disputed','is_fiat_sent','created_at','expires_at', 'buyer_invoice_link','maker_bond_link','taker_bond_link','trade_escrow_link') list_display_links = ('id','type') - change_links = ('maker','taker','buyer_invoice','maker_bond','taker_bond','trade_escrow') + change_links = ('maker','taker','currency','buyer_invoice','maker_bond','taker_bond','trade_escrow') list_filter = ('is_disputed','is_fiat_sent','type','currency','status') @admin.register(LNPayment) @@ -43,8 +43,8 @@ class UserProfileAdmin(AdminChangeLinksMixin, admin.ModelAdmin): change_links =['user'] readonly_fields = ['avatar_tag'] -@admin.register(CachedExchangeRate) -class CachedExchangeRateAdmin(admin.ModelAdmin): +@admin.register(Currency) +class CurrencieAdmin(admin.ModelAdmin): list_display = ('currency','exchange_rate','timestamp') readonly_fields = ('currency','exchange_rate','timestamp') diff --git a/api/logics.py b/api/logics.py index 034dfdff..1fd8105b 100644 --- a/api/logics.py +++ b/api/logics.py @@ -2,7 +2,7 @@ from datetime import time, timedelta from django.utils import timezone from .lightning.node import LNNode -from .models import Order, LNPayment, MarketTick, User, CachedExchangeRate +from .models import Order, LNPayment, MarketTick, User, Currency from decouple import config import math @@ -72,7 +72,7 @@ class Logics(): if order.is_explicit: satoshis_now = order.satoshis else: - exchange_rate = float(CachedExchangeRate.objects.get(currency=order.currency).exchange_rate) + exchange_rate = float(order.currency.exchange_rate) premium_rate = exchange_rate * (1+float(order.premium)/100) satoshis_now = (float(order.amount) / premium_rate) * 100*1000*1000 @@ -80,7 +80,7 @@ class Logics(): def price_and_premium_now(order): ''' computes order premium live ''' - exchange_rate = float(CachedExchangeRate.objects.get(currency=order.currency).exchange_rate) + exchange_rate = float(order.currency.exchange_rate) if not order.is_explicit: premium = order.premium price = exchange_rate * (1+float(premium)/100) @@ -373,7 +373,7 @@ class Logics(): order.last_satoshis = cls.satoshis_now(order) bond_satoshis = int(order.last_satoshis * BOND_SIZE) pos_text = 'Buying' if cls.is_buyer(order, user) else 'Selling' - description = (f"RoboSats - Taking 'Order {order.id}' {pos_text} BTC for {str(float(order.amount)) + Order.currency_dict[str(order.currency)]}" + description = (f"RoboSats - Taking 'Order {order.id}' {pos_text} BTC for {str(float(order.amount)) + str(order.currency)}"# Order.currency_dict[str(order.currency)]}" + " - This is a taker bond, it will freeze in your wallet temporarily and automatically return. It will be charged if you cheat or cancel.") # Gen hold Invoice diff --git a/api/models.py b/api/models.py index 8c2a561c..ee718031 100644 --- a/api/models.py +++ b/api/models.py @@ -15,6 +15,24 @@ MAX_TRADE = int(config('MAX_TRADE')) FEE = float(config('FEE')) BOND_SIZE = float(config('BOND_SIZE')) + +class Currency(models.Model): + + currency_dict = json.load(open('./frontend/static/assets/currencies.json')) + currency_choices = [(int(val), label) for val, label in list(currency_dict.items())] + + currency = models.PositiveSmallIntegerField(choices=currency_choices, null=False, unique=True) + exchange_rate = models.DecimalField(max_digits=10, decimal_places=2, default=None, null=True, validators=[MinValueValidator(0)]) + timestamp = models.DateTimeField(auto_now_add=True) + + def __str__(self): + # returns currency label ( 3 letters code) + return self.currency_dict[str(self.currency)] + + class Meta: + verbose_name = 'Cached market currency' + verbose_name_plural = 'Currencies' + class LNPayment(models.Model): class Types(models.IntegerChoices): @@ -62,6 +80,10 @@ class LNPayment(models.Model): def __str__(self): return (f'LN-{str(self.id)[:8]}: {self.Concepts(self.concept).label} - {self.Status(self.status).label}') + class Meta: + verbose_name = 'Lightning payment' + verbose_name_plural = 'Lightning payments' + class Order(models.Model): class Types(models.IntegerChoices): @@ -87,9 +109,6 @@ class Order(models.Model): FAI = 15, 'Failed lightning network routing' MLD = 16, 'Maker lost dispute' TLD = 17, 'Taker lost dispute' - - currency_dict = json.load(open('./frontend/static/assets/currencies.json')) - currency_choices = [(int(val), label) for val, label in list(currency_dict.items())] # order info status = models.PositiveSmallIntegerField(choices=Status.choices, null=False, default=Status.WFB) @@ -98,7 +117,7 @@ class Order(models.Model): # order details type = models.PositiveSmallIntegerField(choices=Types.choices, null=False) - currency = models.PositiveSmallIntegerField(choices=currency_choices, null=False) + currency = models.ForeignKey(Currency, null=True, on_delete=models.SET_NULL) amount = models.DecimalField(max_digits=9, decimal_places=4, validators=[MinValueValidator(0.00001)]) payment_method = models.CharField(max_length=35, null=False, default="not specified", blank=True) @@ -155,7 +174,7 @@ class Order(models.Model): def __str__(self): # Make relational back to ORDER - return (f'Order {self.id}: {self.Types(self.type).label} BTC for {float(self.amount)} {self.currency_dict[str(self.currency)]}') + return (f'Order {self.id}: {self.Types(self.type).label} BTC for {float(self.amount)} {self.currency}') @receiver(pre_delete, sender=Order) def delete_lnpayment_at_order_deletion(sender, instance, **kwargs): @@ -219,13 +238,6 @@ class Profile(models.Model): def avatar_tag(self): return mark_safe('' % self.get_avatar()) -class CachedExchangeRate(models.Model): - - currency = models.PositiveSmallIntegerField(choices=Order.currency_choices, null=False, unique=True) - exchange_rate = models.DecimalField(max_digits=10, decimal_places=2, default=None, null=True, validators=[MinValueValidator(0)]) - timestamp = models.DateTimeField(auto_now_add=True) - - class MarketTick(models.Model): ''' Records tick by tick Non-KYC Bitcoin price. @@ -242,7 +254,7 @@ class MarketTick(models.Model): price = models.DecimalField(max_digits=10, decimal_places=2, default=None, null=True, validators=[MinValueValidator(0)]) volume = models.DecimalField(max_digits=8, decimal_places=8, default=None, null=True, validators=[MinValueValidator(0)]) premium = models.DecimalField(max_digits=5, decimal_places=2, default=None, null=True, validators=[MinValueValidator(-100), MaxValueValidator(999)], blank=True) - currency = models.PositiveSmallIntegerField(choices=Order.currency_choices, null=True) + currency = models.PositiveSmallIntegerField(choices=Currency.currency_choices, null=True) timestamp = models.DateTimeField(auto_now_add=True) # Relevant to keep record of the historical fee, so the insight on the premium can be better analyzed @@ -259,7 +271,7 @@ class MarketTick(models.Model): elif order.taker_bond.status == LNPayment.Status.LOCKED: volume = order.last_satoshis / 100000000 price = float(order.amount) / volume # Amount Fiat / Amount BTC - market_exchange_rate = float(CachedExchangeRate.objects.get(currency=order.currency).exchange_rate) + market_exchange_rate = float(order.currency.exchange_rate) premium = 100 * (price / market_exchange_rate - 1) tick = MarketTick.objects.create( @@ -273,4 +285,7 @@ class MarketTick(models.Model): def __str__(self): return f'Tick: {str(self.id)[:8]}' + class Meta: + verbose_name = 'Market tick' + verbose_name_plural = 'Market ticks' diff --git a/api/tasks.py b/api/tasks.py index f41c2f03..fc6f65d2 100644 --- a/api/tasks.py +++ b/api/tasks.py @@ -2,7 +2,7 @@ from celery import shared_task from .lightning.node import LNNode from django.contrib.auth.models import User -from .models import LNPayment, Order, CachedExchangeRate +from .models import LNPayment, Order, Currency from .logics import Logics from .utils import get_exchange_rates @@ -55,14 +55,15 @@ def query_all_lnd_invoices(): @shared_task(name="cache_market", ignore_result=True) def cache_market(): - exchange_rates = get_exchange_rates(list(Order.currency_dict.values())) + exchange_rates = get_exchange_rates(list(Currency.currency_dict.values())) results = {} - for val in Order.currency_dict: + for val in Currency.currency_dict: rate = exchange_rates[int(val)-1] # currecies are indexed starting at 1 (USD) - results[val] = {Order.currency_dict[val], rate} + results[val] = {Currency.currency_dict[val], rate} # Create / Update database cached prices - CachedExchangeRate.objects.update_or_create( + Currency.objects.update_or_create( + id = int(val), currency = int(val), # if there is a Cached Exchange rate matching that value, it updates it with defaults below defaults = { diff --git a/api/views.py b/api/views.py index d6a2ee0d..3ddbb600 100644 --- a/api/views.py +++ b/api/views.py @@ -9,7 +9,7 @@ from django.contrib.auth import authenticate, login, logout from django.contrib.auth.models import User from .serializers import ListOrderSerializer, MakeOrderSerializer, UpdateOrderSerializer -from .models import LNPayment, MarketTick, Order +from .models import LNPayment, MarketTick, Order, Currency from .logics import Logics from .utils import get_lnd_version, get_commit_robosats @@ -54,7 +54,7 @@ class MakerView(CreateAPIView): # Creates a new order order = Order( type=type, - currency=currency, + currency=Currency.objects.get(id=currency), amount=amount, payment_method=payment_method, premium=premium,