Convert cached currency to relation children of order

This commit is contained in:
Reckless_Satoshi
2022-01-16 08:06:53 -08:00
parent 185cc71e91
commit 2cbc82a535
5 changed files with 46 additions and 30 deletions

View File

@ -2,7 +2,7 @@ from django.contrib import admin
from django_admin_relation_links import AdminChangeLinksMixin from django_admin_relation_links import AdminChangeLinksMixin
from django.contrib.auth.models import Group, User from django.contrib.auth.models import Group, User
from django.contrib.auth.admin import UserAdmin 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(Group)
admin.site.unregister(User) admin.site.unregister(User)
@ -24,9 +24,9 @@ class EUserAdmin(UserAdmin):
@admin.register(Order) @admin.register(Order)
class OrderAdmin(AdminChangeLinksMixin, admin.ModelAdmin): 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') 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') list_filter = ('is_disputed','is_fiat_sent','type','currency','status')
@admin.register(LNPayment) @admin.register(LNPayment)
@ -43,8 +43,8 @@ class UserProfileAdmin(AdminChangeLinksMixin, admin.ModelAdmin):
change_links =['user'] change_links =['user']
readonly_fields = ['avatar_tag'] readonly_fields = ['avatar_tag']
@admin.register(CachedExchangeRate) @admin.register(Currency)
class CachedExchangeRateAdmin(admin.ModelAdmin): class CurrencieAdmin(admin.ModelAdmin):
list_display = ('currency','exchange_rate','timestamp') list_display = ('currency','exchange_rate','timestamp')
readonly_fields = ('currency','exchange_rate','timestamp') readonly_fields = ('currency','exchange_rate','timestamp')

View File

@ -2,7 +2,7 @@ from datetime import time, timedelta
from django.utils import timezone from django.utils import timezone
from .lightning.node import LNNode 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 from decouple import config
import math import math
@ -72,7 +72,7 @@ class Logics():
if order.is_explicit: if order.is_explicit:
satoshis_now = order.satoshis satoshis_now = order.satoshis
else: 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) premium_rate = exchange_rate * (1+float(order.premium)/100)
satoshis_now = (float(order.amount) / premium_rate) * 100*1000*1000 satoshis_now = (float(order.amount) / premium_rate) * 100*1000*1000
@ -80,7 +80,7 @@ class Logics():
def price_and_premium_now(order): def price_and_premium_now(order):
''' computes order premium live ''' ''' 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: if not order.is_explicit:
premium = order.premium premium = order.premium
price = exchange_rate * (1+float(premium)/100) price = exchange_rate * (1+float(premium)/100)
@ -373,7 +373,7 @@ class Logics():
order.last_satoshis = cls.satoshis_now(order) order.last_satoshis = cls.satoshis_now(order)
bond_satoshis = int(order.last_satoshis * BOND_SIZE) bond_satoshis = int(order.last_satoshis * BOND_SIZE)
pos_text = 'Buying' if cls.is_buyer(order, user) else 'Selling' 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.") + " - 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 # Gen hold Invoice

View File

@ -15,6 +15,24 @@ MAX_TRADE = int(config('MAX_TRADE'))
FEE = float(config('FEE')) FEE = float(config('FEE'))
BOND_SIZE = float(config('BOND_SIZE')) 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 LNPayment(models.Model):
class Types(models.IntegerChoices): class Types(models.IntegerChoices):
@ -62,6 +80,10 @@ class LNPayment(models.Model):
def __str__(self): def __str__(self):
return (f'LN-{str(self.id)[:8]}: {self.Concepts(self.concept).label} - {self.Status(self.status).label}') 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 Order(models.Model):
class Types(models.IntegerChoices): class Types(models.IntegerChoices):
@ -88,9 +110,6 @@ class Order(models.Model):
MLD = 16, 'Maker lost dispute' MLD = 16, 'Maker lost dispute'
TLD = 17, 'Taker 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 # order info
status = models.PositiveSmallIntegerField(choices=Status.choices, null=False, default=Status.WFB) status = models.PositiveSmallIntegerField(choices=Status.choices, null=False, default=Status.WFB)
created_at = models.DateTimeField(auto_now_add=True) created_at = models.DateTimeField(auto_now_add=True)
@ -98,7 +117,7 @@ class Order(models.Model):
# order details # order details
type = models.PositiveSmallIntegerField(choices=Types.choices, null=False) 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)]) 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) 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): def __str__(self):
# Make relational back to ORDER # 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) @receiver(pre_delete, sender=Order)
def delete_lnpayment_at_order_deletion(sender, instance, **kwargs): def delete_lnpayment_at_order_deletion(sender, instance, **kwargs):
@ -219,13 +238,6 @@ class Profile(models.Model):
def avatar_tag(self): def avatar_tag(self):
return mark_safe('<img src="%s" width="50" height="50" />' % self.get_avatar()) return mark_safe('<img src="%s" width="50" height="50" />' % 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): class MarketTick(models.Model):
''' '''
Records tick by tick Non-KYC Bitcoin price. 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)]) 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)]) 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) 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) 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 # 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: elif order.taker_bond.status == LNPayment.Status.LOCKED:
volume = order.last_satoshis / 100000000 volume = order.last_satoshis / 100000000
price = float(order.amount) / volume # Amount Fiat / Amount BTC 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) premium = 100 * (price / market_exchange_rate - 1)
tick = MarketTick.objects.create( tick = MarketTick.objects.create(
@ -273,4 +285,7 @@ class MarketTick(models.Model):
def __str__(self): def __str__(self):
return f'Tick: {str(self.id)[:8]}' return f'Tick: {str(self.id)[:8]}'
class Meta:
verbose_name = 'Market tick'
verbose_name_plural = 'Market ticks'

View File

@ -2,7 +2,7 @@ from celery import shared_task
from .lightning.node import LNNode from .lightning.node import LNNode
from django.contrib.auth.models import User from django.contrib.auth.models import User
from .models import LNPayment, Order, CachedExchangeRate from .models import LNPayment, Order, Currency
from .logics import Logics from .logics import Logics
from .utils import get_exchange_rates from .utils import get_exchange_rates
@ -55,14 +55,15 @@ def query_all_lnd_invoices():
@shared_task(name="cache_market", ignore_result=True) @shared_task(name="cache_market", ignore_result=True)
def cache_market(): def cache_market():
exchange_rates = get_exchange_rates(list(Order.currency_dict.values())) exchange_rates = get_exchange_rates(list(Currency.currency_dict.values()))
results = {} 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) 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 # Create / Update database cached prices
CachedExchangeRate.objects.update_or_create( Currency.objects.update_or_create(
id = int(val),
currency = int(val), currency = int(val),
# if there is a Cached Exchange rate matching that value, it updates it with defaults below # if there is a Cached Exchange rate matching that value, it updates it with defaults below
defaults = { defaults = {

View File

@ -9,7 +9,7 @@ from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.models import User from django.contrib.auth.models import User
from .serializers import ListOrderSerializer, MakeOrderSerializer, UpdateOrderSerializer from .serializers import ListOrderSerializer, MakeOrderSerializer, UpdateOrderSerializer
from .models import LNPayment, MarketTick, Order from .models import LNPayment, MarketTick, Order, Currency
from .logics import Logics from .logics import Logics
from .utils import get_lnd_version, get_commit_robosats from .utils import get_lnd_version, get_commit_robosats
@ -54,7 +54,7 @@ class MakerView(CreateAPIView):
# Creates a new order # Creates a new order
order = Order( order = Order(
type=type, type=type,
currency=currency, currency=Currency.objects.get(id=currency),
amount=amount, amount=amount,
payment_method=payment_method, payment_method=payment_method,
premium=premium, premium=premium,