Skip to content

Commit 7afa79f

Browse files
author
Anh-Duy Le
committed
DLE-190520-Impl a pure LinearRegression method not use 3rd party library
1 parent 0f647ce commit 7afa79f

File tree

11 files changed

+214
-62
lines changed

11 files changed

+214
-62
lines changed

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
__pycache__
2-
.vscode/settings.json
2+
.vscode
33
temp
44
*.pkl
5+
app_build/model_trained
6+
app_build/ExchangeRatesPrediction.exe

__main__.py

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,16 @@ def mainProcess(self):
2727

2828
print("Welcome to Exchange Rates Service!")
2929
option = input("Which services do you want to use?: \
30-
\n1. Predict tight range of matching (Quick process) \
31-
\n2. Predict wide range of matching (Long process) \
32-
\n3. Check exchange rates of specific currency \
33-
\n4. Check all exchange rates \
30+
\n1 - Predict basic matching (Extreme Quick process) \
31+
\n2 - Predict tight range of matching (Quick process) \
32+
\n3 - Predict wide range of matching (Long process) \
33+
\n4 - Check exchange rates of specific currency \
34+
\n5 - Check all exchange rates \
3435
\nAny key to quit... \
3536
\nPlease input your choice's number: ").strip()
3637

3738

38-
while ( option.isdigit() and int(option) > 0 and int(option) < 5 ):
39+
while ( option.isdigit() and int(option) > 0 and int(option) < 6 ):
3940
option = int(option)
4041

4142
checkedDate = input("Which date do you want to check? (YYYY-MM-DD): ").strip()
@@ -46,25 +47,32 @@ def mainProcess(self):
4647
self.validateInput(option, checkedDate, baseCurrency, toCurrency)
4748

4849
service = ExchangeRateService()
49-
data = service.predicted_quick_exrate(self.ApiGetExcRateConfig, self.checkedDate, self.baseCurrency, self.toCurrency)
50+
data = service.predicted_basic_exrate(self.ApiGetExcRateConfig, self.checkedDate, self.baseCurrency, self.toCurrency)
5051
service.display_graph(data)
5152

52-
elif(option == 2):
53+
if(option == 2):
5354
self.validateInput(option, checkedDate, baseCurrency, toCurrency)
54-
checkedDaysPerMonth = 10
5555

5656
service = ExchangeRateService()
57-
data = service.predicted_long_exrate(self.ApiGetExcRateConfig, self.checkedDate, self.baseCurrency, self.toCurrency, checkedDaysPerMonth)
57+
data = service.predicted_quick_exrate_bytrainnedmodel(self.ApiGetExcRateConfig, self.checkedDate, self.baseCurrency, self.toCurrency)
5858
service.display_graph(data)
5959

6060
elif(option == 3):
6161
self.validateInput(option, checkedDate, baseCurrency, toCurrency)
62+
checkedDaysPerMonth = 6
63+
64+
service = ExchangeRateService()
65+
data = service.predicted_long_exrate_bytrainnedmodel(self.ApiGetExcRateConfig, self.checkedDate, self.baseCurrency, self.toCurrency, checkedDaysPerMonth)
66+
service.display_graph(data)
67+
68+
elif(option == 4):
69+
self.validateInput(option, checkedDate, baseCurrency, toCurrency)
6270

6371
service = ExchangeRateService()
6472
data = service.get_specific_exrate_byDate(self.ApiGetExcRateConfig, self.checkedDate, self.baseCurrency, self.toCurrency)
6573
print(str(data.Currency) + " - " + str(data.RateValue))
6674

67-
elif(option == 4):
75+
elif(option == 5):
6876
self.validateInput(option, checkedDate, baseCurrency, toCurrency)
6977

7078
service = ExchangeRateService()
@@ -77,10 +85,11 @@ def mainProcess(self):
7785
print("-"*30 + "PROCESS DONE" + "-"*30)
7886

7987
option = input("Which services do you want to use?: \
80-
\n1. Predict tight range of matching (Quick process) \
81-
\n2. Predict wide range of matching (Long process) \
82-
\n3. Check exchange rates of specific currency \
83-
\n4. Check all exchange rates \
88+
\n1 - Predict basic matching (Extreme Quick process) \
89+
\n2 - Predict tight range of matching (Quick process) \
90+
\n3 - Predict wide range of matching (Long process) \
91+
\n4 - Check exchange rates of specific currency \
92+
\n5 - Check all exchange rates \
8493
\nAny key to quit... \
8594
\nPlease input your choice's number: ").strip()
8695

@@ -93,14 +102,15 @@ def mainProcess(self):
93102
def validateInput(self, option, checkedDate, baseCurrency, toCurrency):
94103
self.baseCurrency = (not baseCurrency) and 'USD' or str(baseCurrency).upper()
95104

96-
currentDate = datetime.date.today()
105+
currentDate = datetime.datetime.today()
97106
if ExchangeRateService().UtilCommon().validateDateFormat(checkedDate):
98-
checkedDate = ExchangeRateService().UtilCommon().parseStringToDateTime(checkedDate).date()
107+
checkedDate = ExchangeRateService().UtilCommon().parseStringToDateTime(checkedDate)
99108
self.checkedDate = (checkedDate >= currentDate) and currentDate or checkedDate
100109
else:
101110
self.checkedDate = currentDate
102111

103-
if(option == 1 or option == 2 or option == 3):
112+
optionNeedToCurreny = [1,2,3,4]
113+
if(option in optionNeedToCurreny):
104114
self.toCurrency = toCurrency
105115
countFail = 0
106116
while not toCurrency:
@@ -121,7 +131,8 @@ def validateInput(self, option, checkedDate, baseCurrency, toCurrency):
121131

122132

123133
### BUILD APP
124-
# Step 1: Put all images folder to "dist" folder (folder to deploy app)
125-
# Step 2: Open CMD/Terminal and change directory path to main python script
126-
# Step 3: Run command in first time => pyinstaller --clean --distpath=./app_build --workpath=./temp --onefile --name ExchangeRatesPrediction ./__main__.py
134+
# Step 1: Put all neccessary media/config files to build folder (folder to deploy app)
135+
# Step 2: Open CMD/Terminal and change directory path to main python script (__main__.py)
136+
# Step 3: Run command pip install these packages: pyinstaller, tornado, pypiwin32
137+
# Step 4: Run command in first time => pyinstaller --clean --distpath=./app_build --workpath=./temp --onefile --name ExchangeRatesPrediction ./__main__.py
127138
# Or Run this command when already have .spec file => pyinstaller --clean --distpath=./app_build --workpath=./temp --add-data="config.json;." --add-data="/model_trained/linear_model.pkl;." --onefile ExchangeRatesPrediction.spec

app_build/ExchangeRatesPrediction.exe

-65 MB
Binary file not shown.
-586 Bytes
Binary file not shown.

config.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
"param_defvalue": "USD"
2323
}
2424
],
25-
"is_using": "False"
25+
"is_using": "True"
2626
},
2727
{
2828
"type": "api",
@@ -37,7 +37,7 @@
3737
"param_defvalue": "USD"
3838
}
3939
],
40-
"is_using": "True"
40+
"is_using": "False"
4141
},
4242
{
4343
"type": "api",

core_utils/util_common.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,12 +78,14 @@ def generateRandomDateInMonth(self, year, month, totalRandom = 1):
7878
currentTotalDays = calendar.monthrange(year, month)[1]
7979

8080
if totalRandom <= currentTotalDays:
81-
dt = random.randint(1, currentTotalDays)
81+
rdt = random.randint(1, currentTotalDays)
82+
d = datetime(year, month, rdt)
8283
# check if random number not exist in list and list size must smaller than total random times
8384
while(len(lstDate) < totalRandom):
84-
if not dt in lstDate:
85-
lstDate.append(dt)
86-
dt = random.randint(1, currentTotalDays)
85+
if not d in lstDate:
86+
lstDate.append(d)
87+
rdt = random.randint(1, currentTotalDays)
88+
d = datetime(year, month, rdt)
8789

8890
return lstDate
8991

core_utils/util_logic.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
2+
class Core_UtilityLogic():
3+
4+
5+
def __init__(self):
6+
pass
7+
8+
def calTotalSumOfSeries(self, lstValue):
9+
try:
10+
if lstValue and len(lstValue) > 0:
11+
return sum(lstValue)
12+
except ValueError as ex:
13+
print('Error: ', ex)
14+
15+
return 0
16+
17+
18+
def calLinearRegressionOfY(self, lstSampleValueX, lstSampleValueY, xVal):
19+
try:
20+
lstSpX = 0
21+
lstSpY = 0
22+
23+
if lstSampleValueX and len(lstSampleValueX) > 0:
24+
lstSpX = lstSampleValueX
25+
if lstSampleValueY and len(lstSampleValueY) > 0:
26+
lstSpY = lstSampleValueY
27+
28+
numberOfVal = (len(lstSpX) > len(lstSpY)) and len(lstSpX) or len(lstSpY)
29+
sumX = self.calTotalSumOfSeries(lstSpX)
30+
sumY = self.calTotalSumOfSeries(lstSpY)
31+
sumXY = sum([x * y for (x, y) in zip(lstSpX, lstSpY)])
32+
sumXX = sum([x * y for (x, y) in zip(lstSpX, lstSpX)])
33+
34+
#the more list of value X and Y passed in, the more calculation for accurate slope and intercept be matched
35+
slope = (numberOfVal*sumXY - sumX*sumY) / (numberOfVal*sumXX - pow(sumX,2))
36+
intercept = (sumY - slope*sumX) / numberOfVal
37+
38+
#calculate approximate Y value (predict Y) for specific X value by regression equation: y = a + bx
39+
equationResult = intercept + slope*xVal
40+
41+
return equationResult
42+
43+
except ValueError as ex:
44+
print('Error: ', ex)
45+
46+
return 0
47+
48+
def calLinearRegressionOfListY(self, lstSampleValueX, lstSampleValueY, lstXVal):
49+
try:
50+
if lstXVal and len(lstXVal) > 0:
51+
lstYVal = []
52+
for x in lstXVal:
53+
y = self.calLinearRegressionOfY(lstSampleValueX, lstSampleValueY, x)
54+
lstYVal.append(y)
55+
56+
return lstYVal
57+
58+
except ValueError as ex:
59+
print('Error: ', ex)
60+
61+
return None
62+

service/banking/exchangerate_service.py

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ def __init__(self):
2727
self.base_service = BaseService()
2828
self.domain_factory = self.base_service.DomainFactory()
2929
self.util_common = self.base_service.UtilCommon()
30-
self.util_data = self.base_service.UtilData()
30+
self.util_data = self.base_service.UtilData()
31+
self.util_logic = self.base_service.UtilLogic()
3132

3233
self.ConfigApiModel = self.domain_factory.init_ModelClass('ConfigApiModel')
3334
self.ConfigApiQueryModel = self.domain_factory.init_ModelClass('ConfigApiQueryModel')
@@ -43,7 +44,8 @@ def get_exrate_byDate(self, apiConfig, dateReport, baseCurrency):
4344
lstCustomizeQuery = []
4445
lstCustomizeQuery.append(modelBaseCurParam)
4546

46-
apiUrl = self.base_service.Config.initApiUrl(apiConfig, dateReport, lstCustomizeQuery)
47+
dateReport = self.util_common.parseStringToDateTime(dateReport)
48+
apiUrl = self.base_service.Config.initApiUrl(apiConfig, dateReport.date(), lstCustomizeQuery)
4749
if apiUrl:
4850
content = self.util_data.readJsonFromUrl(apiUrl)
4951
lstRates = []
@@ -74,20 +76,21 @@ def get_specific_exrate_byDateRange(self, apiConfig, fromDate, toDate, checkedDa
7476
# print('Checked Date: Exchange Rates')
7577
lstExcRates = []
7678
for single_date in self.util_common.dateRange(fromDate, toDate):
77-
if any(da == single_date.day for da in checkedDate):
79+
if any(da == single_date.day for da in [d.day for d in checkedDate]):
7880
data = self.get_specific_exrate_byDate(apiConfig, single_date.strftime("%Y-%m-%d"), baseCurrency, toCurrency)
7981
# print(single_date.strftime("%Y-%m-%d") + ': ' + str(data.RateValue))
8082

8183
model = self.ExchangeRateModel()
8284
model.BaseCurrency = baseCurrency
8385
model.ConvertedCurrency = toCurrency
84-
model.OnDate = single_date.month#datetime.timestamp(single_date)#convert datetime to timestamp
86+
model.OnDate = datetime.timestamp(single_date) #single_date.month
8587
model.RateValue = data.RateValue
8688

8789
lstExcRates.append(model)
8890

8991
return len(lstExcRates) > 0 and lstExcRates or None
9092

93+
9194
def display_graph(self, listdata):
9295

9396
date = [x.OnDate for x in listdata]
@@ -102,6 +105,7 @@ def display_graph(self, listdata):
102105
plt.ylabel("Rates")
103106
plt.show()
104107

108+
105109
def training_linear_model(self, listdata):
106110
date = [[x.OnDate] for x in listdata]
107111
rate = [[x.RateValue] for x in listdata]
@@ -128,14 +132,24 @@ def training_linear_model(self, listdata):
128132
print("Predicted: ", predicted)
129133

130134
return predicted
135+
131136

137+
def calculate_exrate_forSpecificDate(self, listdata, checkedDate):
138+
date = [x.OnDate for x in listdata]
139+
rate = [x.RateValue for x in listdata]
140+
chkDate = datetime.timestamp(checkedDate)
141+
142+
predictedRate = self.util_logic.calLinearRegressionOfY(lstSampleValueX=date, lstSampleValueY=rate, xVal=chkDate)
132143

133-
def predicted_quick_exrate(self, apiConfig, strPredictedDate, baseCurrency, toCurrency):
144+
return predictedRate
145+
146+
147+
def predicted_quick_exrate_bytrainnedmodel(self, apiConfig, strPredictedDate, baseCurrency, toCurrency):
134148
predictedDate = self.util_common.parseStringToDateTime(strPredictedDate)
135149
dateLastMonth = self.util_common.getDateByYearCount(strPredictedDate, -1)
136150
dateLastYear = self.util_common.getDateByMonthCount(strPredictedDate, -1)
137151
checkedDate = []
138-
checkedDate.append(predictedDate.day)
152+
checkedDate.append(predictedDate)
139153

140154

141155
data = self.get_specific_exrate_byDateRange(apiConfig, dateLastMonth, dateLastYear, checkedDate, baseCurrency, toCurrency)
@@ -144,13 +158,14 @@ def predicted_quick_exrate(self, apiConfig, strPredictedDate, baseCurrency, toCu
144158

145159
return data
146160

147-
def predicted_long_exrate(self, apiConfig, strPredictedDate, baseCurrency, toCurrency, checkedDaysPerMonth=5):
161+
162+
def predicted_long_exrate_bytrainnedmodel(self, apiConfig, strPredictedDate, baseCurrency, toCurrency, checkedDaysPerMonth=5):
148163
predictedDate = self.util_common.parseStringToDateTime(strPredictedDate)
149164
dateLastMonth = self.util_common.getDateByYearCount(strPredictedDate, -1)
150165
dateLastYear = self.util_common.getDateByMonthCount(strPredictedDate, -1)
151166
checkedDate = self.util_common.generateRandomDateInMonth(year=predictedDate.year, month=predictedDate.month, totalRandom=checkedDaysPerMonth)
152-
if not predictedDate.day in checkedDate:
153-
checkedDate.append(predictedDate.day)
167+
if not predictedDate in checkedDate:
168+
checkedDate.append(predictedDate)
154169

155170

156171
data = self.get_specific_exrate_byDateRange(apiConfig, dateLastMonth, dateLastYear, checkedDate, baseCurrency, toCurrency)
@@ -159,6 +174,22 @@ def predicted_long_exrate(self, apiConfig, strPredictedDate, baseCurrency, toCur
159174

160175
return data
161176

177+
178+
def predicted_basic_exrate(self, apiConfig, strPredictedDate, baseCurrency, toCurrency):
179+
predictedDate = self.util_common.parseStringToDateTime(strPredictedDate)
180+
dateLastMonth = self.util_common.getDateByYearCount(strPredictedDate, -1)
181+
dateLastYear = self.util_common.getDateByMonthCount(strPredictedDate, -1)
182+
checkedDate = []
183+
checkedDate.append(predictedDate)
184+
185+
data = self.get_specific_exrate_byDateRange(apiConfig, dateLastMonth, dateLastYear, checkedDate, baseCurrency, toCurrency)
186+
187+
predictedRate = self.calculate_exrate_forSpecificDate(data, predictedDate)
188+
print("Predicted: ", predictedRate)
189+
190+
return data
191+
192+
162193

163194

164195

service/base_service.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
from core_utils.util_common import Core_UtilityCommon
1010
from core_utils.util_data import Core_UtilityData
11+
from core_utils.util_logic import Core_UtilityLogic
1112

1213
from domains.domain_factory import DomainFactory
1314
from config import Configuration
@@ -31,6 +32,9 @@ def UtilCommon(self):
3132
def UtilData(self):
3233
return Core_UtilityData()
3334

35+
def UtilLogic(self):
36+
return Core_UtilityLogic()
37+
3438

3539

3640

0 commit comments

Comments
 (0)