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

@ -318,16 +318,11 @@ class Order(models.Model):
3: int(config("EXP_TAKER_BOND_INVOICE")), # 'Waiting for taker bond' 3: int(config("EXP_TAKER_BOND_INVOICE")), # 'Waiting for taker bond'
4: 0, # 'Cancelled' 4: 0, # 'Cancelled'
5: 0, # 'Expired' 5: 0, # 'Expired'
6: 60 * int(config("INVOICE_AND_ESCROW_DURATION") 6: 60 * int(config("INVOICE_AND_ESCROW_DURATION")), # 'Waiting for trade collateral and buyer invoice'
), # 'Waiting for trade collateral and buyer invoice' 7: 60 * int(config("INVOICE_AND_ESCROW_DURATION")), # 'Waiting only for seller trade collateral'
7: 60 * int(config("INVOICE_AND_ESCROW_DURATION") 8: 60 * int(config("INVOICE_AND_ESCROW_DURATION")), # 'Waiting only for buyer invoice'
), # 'Waiting only for seller trade collateral' 9: 60 * 60 * int(config("FIAT_EXCHANGE_DURATION")), # 'Sending fiat - In chatroom'
8: 60 * int(config("INVOICE_AND_ESCROW_DURATION") 10: 60 * 60 * int(config("FIAT_EXCHANGE_DURATION")),# 'Fiat sent - In chatroom'
), # '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' 11: 1 * 24 * 60 * 60, # 'In dispute'
12: 0, # 'Collaboratively cancelled' 12: 0, # 'Collaboratively cancelled'
13: 24 * 60 * 60, # 'Sending satoshis to buyer' 13: 24 * 60 * 60, # 'Sending satoshis to buyer'

View File

@ -72,3 +72,6 @@ class ClaimRewardSerializer(serializers.Serializer):
allow_null=True, allow_null=True,
allow_blank=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 django.urls import path
from .views import MakerView, OrderView, UserView, BookView, InfoView, RewardView from .views import MakerView, OrderView, UserView, BookView, InfoView, RewardView, PriceView
urlpatterns = [ urlpatterns = [
path("make/", MakerView.as_view()), path("make/", MakerView.as_view()),
@ -12,5 +12,6 @@ urlpatterns = [
path("book/", BookView.as_view()), path("book/", BookView.as_view()),
# path('robot/') # Profile Info # path('robot/') # Profile Info
path("info/", InfoView.as_view()), path("info/", InfoView.as_view()),
path("price/", PriceView.as_view()),
path("reward/", RewardView.as_view()), path("reward/", RewardView.as_view()),
] ]

View File

@ -109,3 +109,16 @@ def compute_premium_percentile(order):
rates = np.array(rates) 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 import authenticate, login, logout
from django.contrib.auth.models import User 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.models import LNPayment, MarketTick, Order, Currency, Profile
from api.logics import Logics from api.logics import Logics
from api.messages import Telegram from api.messages import Telegram
from secrets import token_urlsafe 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 .nick_generator.nick_generator import NickGenerator
from robohash import Robohash from robohash import Robohash
@ -655,18 +655,11 @@ class InfoView(ListAPIView):
# Compute average premium and volume of today # Compute average premium and volume of today
queryset = MarketTick.objects.filter(timestamp__day=today.day) queryset = MarketTick.objects.filter(timestamp__day=today.day)
if not len(queryset) == 0: if not len(queryset) == 0:
weighted_premiums = [] avg_premium, total_volume = compute_avg_premium(queryset)
volumes = [] # If no contracts, fallback to lifetime avg premium
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
else: else:
avg_premium = 0 queryset = MarketTick.objects.all()
total_volume = 0 avg_premium, total_volume = compute_avg_premium(queryset)
queryset = MarketTick.objects.all() queryset = MarketTick.objects.all()
if not len(queryset) == 0: if not len(queryset) == 0:
@ -729,6 +722,33 @@ class RewardView(CreateAPIView):
context['successful_withdrawal'] = False context['successful_withdrawal'] = False
return Response(context, status.HTTP_400_BAD_REQUEST) return Response(context, status.HTTP_400_BAD_REQUEST)
return Response({"successful_withdrawal": True}, status.HTTP_200_OK) 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> <ListItemIcon>
<PasswordIcon/> <PasswordIcon/>
</ListItemIcon> </ListItemIcon>
<ListItemText secondary="It will not remain here"> <ListItemText secondary="Your token (will not remain here)">
{this.props.token ? {this.props.token ?
<TextField <TextField
disabled disabled
label='Your Token, back it up!' label='Back it up!'
value={this.props.token } value={this.props.token }
variant='filled' variant='filled'
size='small' 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 = () => { CancelButton = () => {
// If maker and Waiting for Bond. Or if taker and Waiting for bond. // If maker and Waiting for Bond. Or if taker and Waiting for bond.
@ -561,7 +572,10 @@ export default class OrderPage extends Component {
<Grid item xs={12} align="center"> <Grid item xs={12} align="center">
{/* Participants can see the "Cancel" Button, but cannot see the "Back" or "Take Order" buttons */} {/* Participants can see the "Cancel" Button, but cannot see the "Back" or "Take Order" buttons */}
{this.state.is_participant ? {this.state.is_participant ?
<>
<this.CancelButton/> <this.CancelButton/>
<this.BackButton/>
</>
: :
<Grid container spacing={1}> <Grid container spacing={1}>
<Grid item xs={12} align="center"> <Grid item xs={12} align="center">

File diff suppressed because one or more lines are too long