Skip to content

Instantly share code, notes, and snippets.

@u1735067
Last active January 11, 2016 09:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save u1735067/b0c8214c5e251c303ad9 to your computer and use it in GitHub Desktop.
Save u1735067/b0c8214c5e251c303ad9 to your computer and use it in GitHub Desktop.
Script de calcul de marge pour CO32B1 en Python
#!python3
#
# Alexandre Levavasseur - FIP16
# Pour le groupe projet CO32B1
#
# This work is licensed under a Creative Commons
# Attribution-NonCommercial-ShareAlike 4.0 International License
#
# Sources:
# https://docs.python.org/3/library/csv.html
# https://docs.python.org/3/tutorial/datastructures.html
# https://docs.python.org/3/library/functions.html#int
# https://docs.python.org/3.0/library/datetime.html
# https://docs.python.org/3.0/library/time.html#time.strptime
# http://stackoverflow.com/questions/3688602/sum-numbers-in-an-array
# https://docs.python.org/3/library/decimal.html
# http://stackoverflow.com/questions/4053924/python-parse-date-format-ignore-parts-of-string
# https://docs.python.org/3/tutorial/errors.html
# http://stackoverflow.com/questions/3294889/iterating-over-dictionaries-using-for-loops-in-python
#
import csv
from decimal import *
from datetime import datetime
import sys
from pprint import pprint
init_file = "stock_initial.csv"
in_file = "WalletTransactions.csv" # Doit être ordonné par date croissante
products = {} # dict [{'nb': x, 'price': x}, ..] ## Le stock
# #############################################################################
# Initialise le stock ..
#
def constr_init_stock_price():
with open(init_file, newline='') as csvfile:
reader = csv.DictReader(csvfile, delimiter=';')
for row in reader:
data = {'date': datetime.strptime(row['date'], '%d/%m/%Y'),
'nb': int(row['quantity']),
'price': Decimal(row['price'])}
products[row['type']] = [data]
# Construit une liste des (date, qté, prix) par produit
def constr_stock_price():
with open(in_file, newline='') as csvfile:
reader = csv.DictReader(csvfile)
for row in reader:
if (row['transactionType'] == "Buy"):
data = {'date': datetime.strptime(row['date'], '%Y-%m-%d %H:%M:%S'),
# data = {'date': datetime.strptime(row['date'].split(' ')[0], '%Y-%m-%d'),
'nb': int(row['quantity']),
'price': Decimal(row['price'])}
if (not row['type'] in products): # Produit inconnu
products[row['type']] = [data]
# Pas date compliant
# elif (products[row['type']][-1]['price'] == row['price']): # Si le dernier a le même prix
# products[row['type']][-1]['nb'] = products[row['type']][-1]['nb'] + data['quantity']
else: # Ajoute un nouveau prix
products[row['type']].append(data)
return products
# Consomme un produit en stock et retourne la liste des prix d'achat
#
def consume(product, nb, cons_date):
out = [] # Retourne la liste des prix
if (nb > 0):
if (not product in products):
raise Exception('Pas de prix pour ce produit ("%s") ?' % product)
else:
while (nb > 0):
if (not products[product]): # On a vidé les stock ..
raise Exception('Plus de prix pour ce produit ("%s")'% product)
elif (products[product][0]['date'] > cons_date):
raise Exception('Il reste du stock pour ("%s") mais il est ajouté après la vente..'% product)
elif (nb >= products[product][0]['nb']): # On consomme totalement ce prix
nb = nb - products[product][0]['nb']
out.append(products[product].pop(0))
else: # Sinon on prend ce qui nous intéresse et on retire du stock
products[product][0]['nb'] = products[product][0]['nb'] - nb
out.append({'nb': nb, 'price': products[product][0]['price']})
nb = 0
# end while
return out
# end if 2
# end if 1
else:
raise Exception('On retire 0 ?')
# Calcule le montant à partir d'une liste de qté & prix
#
def calc_amount_moy(prices):
amount = Decimal(0)
nb = 0
for line in prices:
amount = amount + line['price']*line['nb']
nb = nb + line['nb'] # Nombre de produits vendus
return amount / nb
# Calcule la marge d'une vente en fonction DES prix d'achats en question
#
def calc_marge(px_vente, pxs_achat):
price = Decimal()
price = px_vente - calc_amount_moy(pxs_achat) # Prix de vente - moyenne prix d'achat
return price
# Calcule la liste des marge&rendement par produit et par transaction
# à partir de la liste des entrées en stock et des ventes
#
def infos_par_trans():
out = {} # dict de {'transId': , 'date': , 'marge': }
with open(in_file, newline='') as csvfile:
reader = csv.DictReader(csvfile)
for row in reader:
if (row['transactionType'] == "Sell"):
if (not row['type'] in out):
out[row['type']] = []
this_date = datetime.strptime(row['date'], '%Y-%m-%d %H:%M:%S')
try:
consomme = consume(row['type'], int(row['quantity']), this_date)
marge = calc_marge(Decimal(row['price']), consomme)
rendement = marge / calc_amount_moy(consomme)
out[row['type']].append({'transId': row['transID'],
'date': this_date,
'nb' : int(row['quantity']),
'marge': marge,
'rendement': rendement})
except Exception as e:
print("/!\ Exception : "+e.args[0])
print("Produit : %s\nDate conso: %s\nProduits restants: " % (row['type'], this_date))
pprint(products[row['type']])
print()
break
return out
# Calcule (moy pondérée) la liste des marge&rendement par produit et par jour
# en partant de la liste des marge par produit et par transaction
def infos_par_day(infos_trans):
infos_day = {}
for produit,translist in infos_trans.items(): # Pour chaque produit
infos_day[produit] = {}
for trans in translist: # Pour chaque date
infos_day[produit][trans['date'].date()] = [];
for search in translist: # On cherche les dates identiques
if (search['date'].date() == trans['date'].date()):
infos_day[produit][trans['date'].date()].append(search)
nb_day = sum(i['nb'] for i in infos_day[produit][trans['date'].date()]) # nombre de produits vendus ce jour
marge_day = sum(i['nb']*i['marge'] for i in infos_day[produit][trans['date'].date()])/nb_day # moy pond.
rendement_day = sum(i['nb']*i['rendement'] for i in infos_day[produit][trans['date'].date()])/nb_day # moy pond.
infos_day[produit][trans['date'].date()] = {'marge': round(marge_day, 2), 'rendement': round(rendement_day, 2)}
return infos_day
def infos_global(infos_trans):
infos_global = {}
for produit,translist in infos_trans.items(): # Pour chaque produit
infos_global[produit] = []
for trans in translist: # Pour chaque date
infos_global[produit].append(trans)
nb_global = sum(i['nb'] for i in infos_global[produit]) # nombre de produits vendus ce jour
marge_global = sum(i['nb']*i['marge'] for i in infos_global[produit])/nb_global # moy pond.
rendement_global = sum(i['nb']*i['rendement'] for i in infos_global[produit])/nb_global # moy pond.
infos_global[produit] = {'marge': round(marge_global, 2), 'rendement': round(rendement_global, 2)}
return infos_global
# #############################################################################
# Execution
# #############################################################################
# Construit la liste des prix en stock
constr_init_stock_price()
constr_stock_price()
# DEBUG & Test
DEBUG = False
#DEBUG = True
if (DEBUG):
pprint(products)
print('--Consommé')
nb = 19
prices = consume('Small Armor Repairer II', nb, datetime.strptime('2010-09-07 00:00:00', '%Y-%m-%d %H:%M:%S'))
pprint(prices)
print('--Restant')
pprint(products['Small Armor Repairer II'])
print('--Amount consommé')
pprint(calc_amount(prices))
print('--Marge calculée')
pprint(calc_marge(Decimal('271999.99'), prices))
print()
### Prix d'achat moyen
#
'''
pxa = {}
with open(init_file, newline='') as csvfile:
reader = csv.DictReader(csvfile, delimiter=';')
for row in reader:
# Pas de vérif
pxa[row['type']] = {datetime.strptime(row['date'], '%d/%m/%Y'): [Decimal(row['price'])]}
with open(in_file, newline='') as csvfile:
reader = csv.DictReader(csvfile)
for row in reader:
if (row['transactionType'] == "Buy"):
pdate = datetime.strptime(row['date'].split(' ')[0], '%Y-%m-%d')
if row['type'] not in pxa:
pxa[row['type']] = {}
if pdate not in pxa[row['type']]:
pxa[row['type']][pdate] = []
pxa[row['type']][pdate].append(Decimal(row['price']))
print('produit,date,prix_achat')
for pname,prod in pxa.items():
for pdate,pval in prod.items():
print('%s,%s,%s' % (pname, pdate.strftime('%Y-%m-%d'), round(sum(pval)/len(pval),2)))
sys.exit(0)
'''
### Qte vendue par jour
#
'''
qd = {}
with open(in_file, newline='') as csvfile:
reader = csv.DictReader(csvfile)
for row in reader:
if (row['transactionType'] == "Sell"):
this_date = datetime.strptime(row['date'].split(' ')[0], '%Y-%m-%d')
if row['type'] not in qd:
qd[row['type']] = {}
if this_date not in qd[row['type']]:
qd[row['type']][this_date] = int(row['quantity'])
else:
qd[row['type']][this_date] += int(row['quantity'])
print('produit,date,prix_achat')
for pname,prod in qd.items():
for pdate,pval in prod.items():
print('%s,%s,%s' % (pname, pdate.strftime('%Y-%m-%d'), pval))
sys.exit(0)
'''
# Main
infos_trans = infos_par_trans()
if (DEBUG):
pprint(infos_trans)
fin = infos_par_day(infos_trans)
fin2 = infos_global(infos_trans)
if (DEBUG):
pprint(fin)
pprint(fin2)
if (DEBUG):
pprint(len(products))
pprint(len(infos_trans)) # 1 produit n'est pas vendu
pprint(len(fin))
pprint(len(fin2))
type = "global"
if (type == "day"):
print("produit,date,marge,rendement")
for produit,marges in fin.items():
for date, infos in marges.items():
print("%s,%s,%s,%s" % (produit, date.strftime('%Y-%m-%d'), str(infos['marge']), str(infos['rendement'])))
elif (type == "global"):
print("produit,marge,rendement")
for produit,infos in fin2.items():
print("%s,%s,%s" % (produit, str(infos['marge']), str(infos['rendement'])))
else:
print('lol')
sys.exit(0)
## POUR PIERRE ##
# you owe me :p
#
def calc_val_stock(calc_date):
val = Decimal(0)
for name,product in products.items():
for stock in product:
if (stock['date'] <= calc_date):
val = val + stock['nb']*stock['price']
return val
#
#
current_date = datetime.strptime('2010-07-17 00:00:00', '%Y-%m-%d %H:%M:%S')
with open(in_file, newline='') as csvfile:
reader = csv.DictReader(csvfile)
for row in reader:
if (row['transactionType'] == "Sell"):
this_date = datetime.strptime(row['date'].split(' ')[0], '%Y-%m-%d')
if (current_date != this_date):
print(current_date.strftime('%Y-%m-%d')+" : "+str(calc_val_stock(current_date)))
current_date = this_date
consume(row['type'], int(row['quantity']), this_date)
##
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment