Skip to content

Commit

Permalink
Merge pull request #451 from bounswe/feature/BE-stock-indices
Browse files Browse the repository at this point in the history
Add stock indices endpoint
  • Loading branch information
rukiyeaslan authored Dec 10, 2024
2 parents be6c42d + fa85bdd commit 0f0716a
Show file tree
Hide file tree
Showing 8 changed files with 200 additions and 6 deletions.
8 changes: 5 additions & 3 deletions backend/marketfeed/management/commands/update_currencies.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,20 @@

class Command(BaseCommand):
help = 'Update or Insert the supported currencies to db'

print("currency command")
def handle(self, *args, **kwargs):
# Define the file path (assuming it's inside a 'currency_data' folder)
file_path = os.path.join(settings.BASE_DIR,'marketfeed', 'management', 'currencies.json')

print("currencies")
# Check if the file exists
if not os.path.exists(file_path):
self.stdout.write(self.style.ERROR(f'Currency data file not found: {file_path}'))
return

print("filepath", file_path)
with open(file_path, 'r') as file:
currencies_data = json.load(file)
print(currencies_data)


for currency_data in currencies_data:
code = currency_data.get('code')
Expand Down
5 changes: 4 additions & 1 deletion backend/marketfeed/management/commands/update_stocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def notStock(stockName):

class Command(BaseCommand):
help = 'Update or Insert the Turkish stock market stocks to db'

print("update stocks")

def handle(self, *args, **kwargs):
# Url to fetch stock list
Expand All @@ -20,7 +20,10 @@ def handle(self, *args, **kwargs):
response = requests.get(url)
response.raise_for_status()
stocks = response.json().get('data', [])
print(stocks)
currency = Currency.objects.get(code='TRY')
print(currency)

for stock in stocks:
try:
if notStock(stock['ad']):
Expand Down
21 changes: 21 additions & 0 deletions backend/marketfeed/migrations/0004_index.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Generated by Django 4.2 on 2024-12-04 22:31

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('marketfeed', '0003_stock_last_price_stock_last_updated'),
]

operations = [
migrations.CreateModel(
name='Index',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=50, unique=True)),
('stocks', models.ManyToManyField(to='marketfeed.stock', verbose_name='list of stocks in the index')),
],
),
]
24 changes: 24 additions & 0 deletions backend/marketfeed/migrations/0005_index_currency_index_symbol.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Generated by Django 4.2 on 2024-12-06 20:40

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
('marketfeed', '0004_index'),
]

operations = [
migrations.AddField(
model_name='index',
name='currency',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='marketfeed.currency'),
),
migrations.AddField(
model_name='index',
name='symbol',
field=models.CharField(max_length=250, null=True, unique=True),
),
]
6 changes: 6 additions & 0 deletions backend/marketfeed/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,9 @@ class Comment(models.Model):
user_id=models.ForeignKey(User, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
content = models.CharField(max_length=250)

class Index(models.Model):
name = models.CharField(max_length=50, unique=True)
symbol = models.CharField(max_length=250, unique=True, null=True)
currency = models.ForeignKey(Currency, on_delete=models.CASCADE, null=True)
stocks = models.ManyToManyField(Stock, verbose_name='list of stocks in the index')
64 changes: 63 additions & 1 deletion backend/marketfeed/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,4 +173,66 @@ def create(self, validated_data):
post.portfolios.set(portfolios)

return post


# TODO delete this


class StockListSerializer(serializers.ModelSerializer):
currency = CurrencySerializer()

class Meta:
model = Stock
fields = ['symbol','currency']

def __init__(self, *args, **kwargs):
super(StockListSerializer, self).__init__(*args, **kwargs)


class IndexListSerializer(serializers.ModelSerializer):
#stocks = serializers.PrimaryKeyRelatedField(queryset=Stock.objects.all(), many=True)
#stocks = StockSerializer(many=True)
# TODO should populate stocks but by fetching all of their prices at once.
stocks = StockListSerializer(many=True)
currency = CurrencySerializer()
class Meta:
model = Index
fields = ['id', 'name','symbol','currency', 'stocks']

def __init__(self, *args, **kwargs):
super(IndexListSerializer, self).__init__(*args, **kwargs)

request = self.context.get('request', None)

if request and request.method == 'PUT':
self.fields['name'].required = False
self.fields['stocks'].required = False

elif request and request.method == 'POST':
self.fields['name'].required = True
self.fields['stocks'].required = False

class IndexSerializer(serializers.ModelSerializer):
stocks = serializers.PrimaryKeyRelatedField(queryset=Stock.objects.all(), many=True)
#stocks = StockSerializer(many=True)
# TODO should populate stocks but by fetching all of their prices at once.
#stocks = StockListSerializer(many=True)
currency = serializers.PrimaryKeyRelatedField(queryset=Currency.objects.all())
class Meta:
model = Index
fields = ['id', 'name','symbol','currency', 'stocks']

def __init__(self, *args, **kwargs):
super(IndexSerializer, self).__init__(*args, **kwargs)

request = self.context.get('request', None)

if request and request.method == 'PUT':
self.fields['name'].required = False
self.fields['stocks'].required = False

elif request and request.method == 'POST':
self.fields['name'].required = True
self.fields['stocks'].required = False



4 changes: 3 additions & 1 deletion backend/marketfeed/urls.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import CurrencyViewSet, StockViewSet, TagViewSet, PortfolioViewSet, PostViewSet, CommentViewSet
from .views import CurrencyViewSet, StockViewSet, TagViewSet, PortfolioViewSet, PostViewSet, CommentViewSet, IndexViewSet

router = DefaultRouter()
router.register(r'currencies', CurrencyViewSet)
Expand All @@ -9,6 +9,8 @@
router.register(r'portfolios', PortfolioViewSet)
router.register(r'posts', PostViewSet)
router.register(r'comments', CommentViewSet)
router.register(r'indices', IndexViewSet)


urlpatterns = [
path('', include(router.urls)),
Expand Down
74 changes: 74 additions & 0 deletions backend/marketfeed/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
from .models import *
from rest_framework.decorators import action
from drf_yasg.utils import swagger_auto_schema
import yfinance as yf
from concurrent.futures import ThreadPoolExecutor


class CurrencyViewSet(viewsets.ModelViewSet):
Expand Down Expand Up @@ -258,3 +260,75 @@ def destroy(self, request, pk=None):
comment = self.get_object()
comment.delete()
return Response(status=status.HTTP_204_NO_CONTENT)



class IndexViewSet(viewsets.ModelViewSet):
queryset = Index.objects.all()
serializer_class = IndexSerializer
permission_classes = [permissions.IsAuthenticatedOrReadOnly]

def list(self, request):
if request.method == 'GET':
self.serializer_class = IndexListSerializer
indices = self.get_queryset()
serializer = self.get_serializer(indices, many=True)
serializerData = serializer.data
symbols = [index['symbol'] + '.IS' if index['currency']['code'] == 'TRY' else index['symbol'] for index in serializerData]
data = yf.download(tickers= symbols, period='1d', interval='1d')

prices = {
symbol.split('.')[0]: float(data['Close'][symbol])
for symbol in symbols
}

for index in serializerData:
index['price'] = prices[index['symbol']]
print(serializerData)
return Response(serializer.data)


def retrieve(self, request, pk=None):
if request.method == 'GET':
self.serializer_class = IndexListSerializer
index = self.get_object()
serializer = self.get_serializer(index)
serializerData = serializer.data

indexName = serializerData['symbol']
if serializerData['currency']['code'] == 'TRY':
indexName += '.IS'
data = yf.download(tickers= indexName, period='1d', interval='1d')
serializerData['price'] = data['Close'].values[0][0]

stocks = []
def get_stats(ticker):
info = yf.Ticker(ticker).info

stockInfo = {"currency": info['currency'], "symbol": info['symbol'], "price": info['currentPrice']}
stocks.append(stockInfo)

ticker_list = [a['symbol'] + '.IS' if a["currency"]["code"] == 'TRY' else a['symbol'] for a in serializerData['stocks']]
with ThreadPoolExecutor() as executor:
executor.map(get_stats, ticker_list)

serializerData['stocks'] = stocks
return Response(serializerData)

def create(self, request):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)

def update(self, request, pk=None):
index = self.get_object()
serializer = self.get_serializer(index, data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data)

def destroy(self, request, pk=None):
index = self.get_object()
index.delete()
return Response(status=status.HTTP_204_NO_CONTENT)

0 comments on commit 0f0716a

Please sign in to comment.