Implement public API non-KYC BTC prices

This commit is contained in:
Reckless_Satoshi 2022-03-12 03:24:11 -08:00
parent 408516241d
commit f383d20c37
No known key found for this signature in database
GPG Key ID: 9C4585B561315571
8 changed files with 92 additions and 46 deletions

View File

@ -312,30 +312,25 @@ class Order(models.Model):
taker_platform_rated = models.BooleanField(default=False, null=False)
t_to_expire = {
0: int(config("EXP_MAKER_BOND_INVOICE")), # 'Waiting for maker bond'
0: int(config("EXP_MAKER_BOND_INVOICE")), # 'Waiting for maker bond'
1: 60 * 60 * int(config("PUBLIC_ORDER_DURATION")), # 'Public'
2: 0, # 'Deleted'
3: int(config("EXP_TAKER_BOND_INVOICE")), # 'Waiting for taker bond'
4: 0, # 'Cancelled'
5: 0, # 'Expired'
6: 60 * int(config("INVOICE_AND_ESCROW_DURATION")
), # 'Waiting for trade collateral and buyer invoice'
7: 60 * int(config("INVOICE_AND_ESCROW_DURATION")
), # 'Waiting only for seller trade collateral'
8: 60 * int(config("INVOICE_AND_ESCROW_DURATION")
), # 'Waiting only for buyer invoice'
9: 60 * 60 *
int(config("FIAT_EXCHANGE_DURATION")), # 'Sending fiat - In chatroom'
10: 60 * 60 *
int(config("FIAT_EXCHANGE_DURATION")), # 'Fiat sent - In chatroom'
11: 1 * 24 * 60 * 60, # 'In dispute'
12: 0, # 'Collaboratively cancelled'
13: 24 * 60 * 60, # 'Sending satoshis to buyer'
14: 24 * 60 * 60, # 'Sucessful trade'
15: 24 * 60 * 60, # 'Failed lightning network routing'
16: 10 * 24 * 60 * 60, # 'Wait for dispute resolution'
17: 24 * 60 * 60, # 'Maker lost dispute'
18: 24 * 60 * 60, # 'Taker lost dispute'
2: 0, # 'Deleted'
3: int(config("EXP_TAKER_BOND_INVOICE")), # 'Waiting for taker bond'
4: 0, # 'Cancelled'
5: 0, # 'Expired'
6: 60 * int(config("INVOICE_AND_ESCROW_DURATION")), # 'Waiting for trade collateral and buyer invoice'
7: 60 * int(config("INVOICE_AND_ESCROW_DURATION")), # 'Waiting only for seller trade collateral'
8: 60 * int(config("INVOICE_AND_ESCROW_DURATION")), # 'Waiting only for buyer invoice'
9: 60 * 60 * int(config("FIAT_EXCHANGE_DURATION")), # 'Sending fiat - In chatroom'
10: 60 * 60 * int(config("FIAT_EXCHANGE_DURATION")),# 'Fiat sent - In chatroom'
11: 1 * 24 * 60 * 60, # 'In dispute'
12: 0, # 'Collaboratively cancelled'
13: 24 * 60 * 60, # 'Sending satoshis to buyer'
14: 24 * 60 * 60, # 'Sucessful trade'
15: 24 * 60 * 60, # 'Failed lightning network routing'
16: 10 * 24 * 60 * 60, # 'Wait for dispute resolution'
17: 24 * 60 * 60, # 'Maker lost dispute'
18: 24 * 60 * 60, # 'Taker lost dispute'
}
def __str__(self):

View File

@ -71,4 +71,7 @@ class ClaimRewardSerializer(serializers.Serializer):
invoice = serializers.CharField(max_length=2000,
allow_null=True,
allow_blank=True,
default=None)
default=None)
class PriceSerializer(serializers.Serializer):
pass

View File

@ -1,5 +1,5 @@
from django.urls import path
from .views import MakerView, OrderView, UserView, BookView, InfoView, RewardView
from .views import MakerView, OrderView, UserView, BookView, InfoView, RewardView, PriceView
urlpatterns = [
path("make/", MakerView.as_view()),
@ -12,5 +12,6 @@ urlpatterns = [
path("book/", BookView.as_view()),
# path('robot/') # Profile Info
path("info/", InfoView.as_view()),
path("price/", PriceView.as_view()),
path("reward/", RewardView.as_view()),
]

View File

@ -108,4 +108,17 @@ def compute_premium_percentile(order):
float(similar_order.last_satoshis) / float(similar_order.amount))
rates = np.array(rates)
return round(np.sum(rates < order_rate) / len(rates), 2)
return round(np.sum(rates < order_rate) / len(rates), 2)
def compute_avg_premium(queryset):
weighted_premiums = []
volumes = []
for tick in queryset:
weighted_premiums.append(tick.premium * tick.volume)
volumes.append(tick.volume)
total_volume = sum(volumes)
# Avg_premium is the weighted average of the premiums by volume
avg_premium = sum(weighted_premiums) / total_volume
return avg_premium, total_volume

View File

@ -9,12 +9,12 @@ from rest_framework.response import Response
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.models import User
from api.serializers import ListOrderSerializer, MakeOrderSerializer, UpdateOrderSerializer, ClaimRewardSerializer
from api.serializers import ListOrderSerializer, MakeOrderSerializer, UpdateOrderSerializer, ClaimRewardSerializer, PriceSerializer
from api.models import LNPayment, MarketTick, Order, Currency, Profile
from api.logics import Logics
from api.messages import Telegram
from secrets import token_urlsafe
from api.utils import get_lnd_version, get_commit_robosats, compute_premium_percentile
from api.utils import get_lnd_version, get_commit_robosats, compute_premium_percentile, compute_avg_premium
from .nick_generator.nick_generator import NickGenerator
from robohash import Robohash
@ -655,18 +655,11 @@ class InfoView(ListAPIView):
# Compute average premium and volume of today
queryset = MarketTick.objects.filter(timestamp__day=today.day)
if not len(queryset) == 0:
weighted_premiums = []
volumes = []
for tick in queryset:
weighted_premiums.append(tick.premium * tick.volume)
volumes.append(tick.volume)
total_volume = sum(volumes)
# Avg_premium is the weighted average of the premiums by volume
avg_premium = sum(weighted_premiums) / total_volume
avg_premium, total_volume = compute_avg_premium(queryset)
# If no contracts, fallback to lifetime avg premium
else:
avg_premium = 0
total_volume = 0
queryset = MarketTick.objects.all()
avg_premium, total_volume = compute_avg_premium(queryset)
queryset = MarketTick.objects.all()
if not len(queryset) == 0:
@ -729,6 +722,33 @@ class RewardView(CreateAPIView):
context['successful_withdrawal'] = False
return Response(context, status.HTTP_400_BAD_REQUEST)
return Response({"successful_withdrawal": True}, status.HTTP_200_OK)
class PriceView(CreateAPIView):
serializer_class = PriceSerializer
def get(self, request):
# Compute average premium and volume of last 24 h
start_datetime = timezone.now() - timedelta(days=1)
queryset = MarketTick.objects.filter(timestamp__gt=start_datetime)
if not len(queryset) == 0:
avg_premium, _ = compute_avg_premium(queryset)
# If no contracts exists in the last 24 h, fallback to lifetime average premium.
else:
queryset = MarketTick.objects.all()
avg_premium, _ = compute_avg_premium(queryset)
payload = {}
queryset = Currency.objects.all().order_by('currency')
for currency in queryset:
code = Currency.currency_dict[str(currency.currency)]
payload[code] = {'price': currency.exchange_rate * (1 + avg_premium / 100),
'premium': avg_premium}
# A hack here. BTC swaps have usually no premium (at least, they are totally different)
payload['BTC'] = {'price': 1, 'premium': 0}
return Response(payload, status.HTTP_200_OK)

View File

@ -315,11 +315,11 @@ export default class BottomBar extends Component {
<ListItemIcon>
<PasswordIcon/>
</ListItemIcon>
<ListItemText secondary="It will not remain here">
<ListItemText secondary="Your token (will not remain here)">
{this.props.token ?
<TextField
disabled
label='Your Token, back it up!'
label='Back it up!'
value={this.props.token }
variant='filled'
size='small'

View File

@ -367,6 +367,17 @@ export default class OrderPage extends Component {
)
}
BackButton = () => {
// If order has expired, show back button.
if (this.state.status == 5){
return(
<Grid item xs={12} align="center">
<Button variant='contained' color='secondary' onClick={this.props.history.goBack}>Back</Button>
</Grid>
)}
return(null)
}
CancelButton = () => {
// If maker and Waiting for Bond. Or if taker and Waiting for bond.
@ -560,8 +571,11 @@ export default class OrderPage extends Component {
<Grid item xs={12} align="center">
{/* Participants can see the "Cancel" Button, but cannot see the "Back" or "Take Order" buttons */}
{this.state.is_participant ?
<this.CancelButton/>
{this.state.is_participant ?
<>
<this.CancelButton/>
<this.BackButton/>
</>
:
<Grid container spacing={1}>
<Grid item xs={12} align="center">

File diff suppressed because one or more lines are too long