Is there better way to improve my algorithm of finding drawdown in stock market? - algorithm

I am trying to calculate drawdowns of every stock.
Definition of drawdown is
A drawdown is a peak-to-trough decline during a specific period for an investment, trading account, or fund.
To put it simple, drawdown is how much does stock crash from peak to trough.
In addition to that, drawdown is recorded when peak's price has recovered later at some point.
To calculate drawdown, I break up into 2 points
find peak(which price is greater than 2 adjacent days' prices)
and trough (which price is lower than 2 adjacent days' prices)
When the peak's price has recovered, that peak, trough becomes a drawdown
Here is an example of stock quotation:
data class Quote(val price: Int, val date: String)
...
//example of quote
Quote(price:1, date:"20080102"),
Quote(price:2, date:"20080103"),
Quote(price:3, date:"20080104"),
Quote(price:1, date:"20080107"),
Quote(price:2, date:"20080108"),
Quote(price:3, date:"20080109"),
Quote(price:2, date:"20080110"),
Quote(price:4, date:"20080111"),
Quote(price:5, date:"20080114"),
Quote(price:6, date:"20080115"),
Quote(price:7, date:"20080116"),
Quote(price:8, date:"20080117"),
Quote(price:9, date:"20080118"),
Quote(price:7, date:"20080122"),
Quote(price:6, date:"20080123"),
Quote(price:8, date:"20080124"),
Quote(price:11,date:"20080125"),
list of drawdowns by date:
(peak: "20080104", trough:"20080107", daysTakenToRecover: 3),
(peak: "20080109", trough:"20080110", daysTakenToRecover: 2),
(peak: "20080118", trough:"20080123", daysTakenToRecover: 4),
Here is what is wrote for a test case:
class Drawdown {
var peak: Quote? = null
var trough: Quote? = null
var recovered: Quote? = null
var percentage: Double? = null
var daysToRecover: String? = null
}
data class Quote(
val price: Double,
val date: String
)
class Test {
private fun findDrawdowns(): List<Drawdown> {
val list = mutableListOf<Drawdown>()
var peak: Quote? = null
var trough: Quote? = null
var recovered: Quote? = null
for (quotation in quotations) {
val currentIdx = quotations.indexOf(quotation)
if (currentIdx in 1 until quotations.size - 1) {
val prevClosing = quotations[currentIdx - 1].price
val nextClosing = quotations[currentIdx + 1].price
val closing = quotation.price
recovered = when {
peak == null -> null
closing >= peak.price -> {
if (peak.date != quotation.date) {
//can possibly be new peak
Quote(closing, quotation.date)
} else null
}
else -> null
}
peak = if (closing > prevClosing && closing > nextClosing) {
if ((peak == null || peak.price < closing) && recovered == null) {
Quote(closing, quotation.date)
} else peak
} else peak
trough = if (closing < prevClosing && closing < nextClosing) {
if (trough == null || trough.price > closing) {
Quote(closing, quotation.date)
} else trough
} else trough
if (recovered != null) {
val drawdown = Drawdown()
val percentage = (peak!!.price - trough!!.price) / peak.price
drawdown.peak = peak
drawdown.trough = trough
drawdown.recovered = recovered
drawdown.percentage = percentage
drawdown.daysToRecover =
ChronoUnit.DAYS.between(
LocalDate.of(
peak.date.substring(0, 4).toInt(),
peak.date.substring(4, 6).toInt(),
peak.date.substring(6, 8).toInt()
),
LocalDate.of(
recovered.date.substring(0, 4).toInt(),
recovered.date.substring(4, 6).toInt(),
recovered.date.substring(6, 8).toInt()
).plusDays(1)
).toString()
list += drawdown
peak = if (closing > prevClosing && closing > nextClosing) {
Quote(recovered.price, recovered.date)
} else {
null
}
trough = null
recovered = null
}
}
}
val drawdown = Drawdown()
val percentage = (peak!!.price - trough!!.price) / peak.price
drawdown.peak = peak
drawdown.trough = trough
drawdown.recovered = recovered
drawdown.percentage = percentage
list += drawdown
return list
}
For those who want to read my code in github, here is a gist:
Find Drawdown in Kotlin, Click Me!!!
I ran some test cases and it shows no error.
So far, I believe this takes an O(n), but I want to make it more efficient.
How can I improve it? Any comments, thoughts are all welcomed!
Thank you and happy early new year.

There are two points
unfortunately the current complexity is the O(N^2)
for (quotation in quotations) {
val currentIdx = quotations.indexOf(quotation)
....
You have a loop through all the quotations, in which for each quotation you find its index. Finding the index is O(N) - look at indexOf docs. So total complexity will be O(N^2)
But you can easy fix it to O(N). Just replace foreach loop + indexOf with forEachIndexed, for example:
quotations.forEachIndexed { index, quote ->
// TODO
}
I think it's not possible to make it faster than O(N), because you need to check each quotation.

Related

How do I get historical candlestick data or kline from Phemex Public API?

I need to be able to extract historical candlestick data (such as Open, Close, High, Low, and Volume) of a candlestick in differing intervals (1m, 3m, 5m, 1H, etc.) at a specified time (timestamps) from Phemex.
Other exchanges, such as Binance or FTX, seem to provide REST Websocket API for this, yet I can't seem to find one for Phemex. Mind helping me resolve this issue? Thank you so much.
Steps I have taken, yet found no resolution:
Went to https://phemex.com/user-guides/api-overview
Went to https://github.com/phemex/phemex-api-docs/blob/master/Public-Contract-API-en.md
None of the items listed in 'Market Data API List' seem to do the task
This code will get the candels and save them to a csv file. Hope this helps:)
exchange = ccxt.phemex({
'options': { 'defaultType': 'swap' },
'enableRateLimit': True
})
# Load the markets
markets = exchange.load_markets()
curent_time = int(time.time()*1000)
one_min = 60000
def get_all_candels(symbol,start_time,stop_time):
counter = 0
candel_counter = 0
data_set = []
t = 0
while t < stop_time:
if data_set == []:
block = exchange.fetch_ohlcv(symbol,'1m',start_time)
for candle in block:
if candle == []:
break
data_set.append(candle)
last_time_in_block = block[-1][0]
counter += 1
candel_counter += len(block)
print(f'{counter} - {block[0]} - {candel_counter} - {last_time_in_block}')
if data_set != []:
t = last_time_in_block + one_min
block = exchange.fetch_ohlcv(symbol,'1m',t)
if block == []:
break
for candle in block:
if candle == []:
break
data_set.append(candle)
last_time_in_block = block[-1][0]
candel_counter += len(block)
counter += 1
print(f'{counter} - {block[0]} - {candel_counter} - {last_time_in_block}')
time.sleep(1)
return data_set
data_set = get_all_candels('BTCUSD',1574726400000,curent_time)
print(np.shape(data_set))
with open('raw.csv', 'w', newline='') as csv_file:
column_names = ['time', 'open', 'high', 'low', 'close', 'volume']
csv_writer = csv.DictWriter(csv_file,fieldnames=column_names)
csv_writer.writeheader()
for candel in data_set:
csv_writer.writerow({
'time':candel[0],
'open':candel[1],
'high':candel[2],
'low':candel[3],
'close':candel[4],
'volume':candel[5]
})

LINQ query slow - nested Group By and ToList()

I have the following linq query that takes 10 seconds or more to run - is there a better way of writing it? It works, but is just very slow:
var searchQuery = (from p in db.Property
where p.PropertyVendorId == loggedInUserId
from aues in db.ApplicationUserEvents
where aues.ApplicationUserEventsPropertyId == p.PropertyId
&& aues.ApplicationUserEventsFeedbackDate != null
group p by new { p.PropertyId, p.PropertyAddress1, p.PropertyAddress2, p.PropertyAddress3, p.PropertyZipOrPostcode } into pg
select new DashboardFeedback
{
PropertyNumber = pg.FirstOrDefault().PropertyNumber,
PropertyId = pg.FirstOrDefault().PropertyId,
PropertyReference = pg.FirstOrDefault().PropertyId,
PropertyAddress1 = pg.FirstOrDefault().PropertyAddress1,
PropertyAddress2 = pg.FirstOrDefault().PropertyAddress2,
PropertyZipOrPostcode = pg.FirstOrDefault().PropertyZipOrPostcode,
DashboardFeedbackChart = (
from aues2 in db.ApplicationUserEvents
where aues2.ApplicationUserEventsPropertyId == pg.FirstOrDefault().PropertyId
&& aues2.ApplicationUserEventsFeedbackDate != null
from fos in db.FeedbackOptions
where fos.FeedbackOptionsApplicationUserEventsId == aues2.ApplicationUserEventsId
from fo in db.FeedbackOption
where fos.FeedbackOptionsFeedbackOptionId == fo.FeedbackOptionId
group fo by new { fo.FeedbackOptionName, aues2.ApplicationUserEventsPropertyId } into g
select new DashboardFeedbackChart
{
FeedbackOptionName = g.FirstOrDefault().FeedbackOptionName,
FeedbackOptionNameCount = g.Count()
}).ToList<DashboardFeedbackChart>()
}).ToList();
One Property has many ApplicationUserEvents
One ApplicationUserEvents has many FeedbackOptions
One FeedbackOptions has one FeedbackOption
Thanks for any advice!

how to find value with path x Groovy

please advise how to find and output cust_JiraTaskId. I need the value of cust_JiraTaskId based on the max number of inside node . In this example it'll be 111111.
I managed to find the max externalCode and now i need cust_JiraTaskId value.
<SFOData.cust_JiraReplication>
<cust_HRISId>J000009</cust_HRISId>
<externalCode>7</externalCode>
<cust_JiraTask>
<externalCode>3</externalCode>
<cust_JiraTaskId>12345</cust_JiraTaskId>
</cust_JiraTask>
<cust_JiraTask>
<externalCode>5</externalCode>
<cust_JiraTaskId>111111</cust_JiraTaskId>
</cust_JiraTask>
</SFOData.cust_JiraReplication>
My script is below
// Create an XPath statement to search for the
element or elements you care about:
XPath x;
x = XPath.newInstance("//cust_JiraTask/externalCode");
myElements = x.selectNodes(doc);
String maxvalue = "";
for (Element myElement : myElements) {
if (myElement.getValue() > maxvalue)
{
maxvalue = myElement.getValue();
}
}
props.setProperty("document.dynamic.userdefined.externalCode", maxvalue);
thanks for help.
This works for me with Groovy 2.4.5:
def xml = """
<SFOData.cust_JiraReplication>
<cust_HRISId>J000009</cust_HRISId>
<externalCode>7</externalCode>
<cust_JiraTask>
<externalCode>3</externalCode>
<cust_JiraTaskId>12345</cust_JiraTaskId>
</cust_JiraTask>
<cust_JiraTask>
<externalCode>5</externalCode>
<cust_JiraTaskId>111111</cust_JiraTaskId>
</cust_JiraTask>
</SFOData.cust_JiraReplication>
"""
def xs = new XmlSlurper().parseText(xml)
def nodes = xs.cust_JiraTask.cust_JiraTaskId
def maxNode = nodes.max { it.text() as int }
assert 111111 == maxNode.text() as int

Grouping data in mapReduce

I have a csv file which I have loaded into hadoop. Data sample is below.
name | shop | balance
tom | shop a | -500
john | shop b | 200
jane | shop c | 5000
Results:
bad 1
normal 1
wealthy 1
I have to get the balance for each person and then put them into groups(bad(<0), normal(1 to 500), good(>500)
I'm not 100% sure how to put the groups into mapReduce. Do I put it in the reducer? or mapper?
Splitting the csv file(mapper):
String[] tokens = value.toString().split(",");
Sting balance = tokens[3];
Creating groups:
String[] category = new String[3];
category[0] = "Bad"
category[1] = "Normal"
category[2] = "Good"
I also have this if/else statement:
if (bal =< 500){
//put into cat 0
} else if ( bal >= 501 && bal <=1500){
// put into cat 1
} else {
//put into cat 2
}
Thanks in advance.
A simple way to implement this would be:
Map:
map() {
if (bal <= 0) { //or 500, or whatever
emit (bad, 1);
} else if (bal <= 500) { // or 1500, or whatever
emit (normal, 1);
} else {
emit (good, 1);
}
}
Reduce (and combiner, as well):
reduce(key, values) {
int count = 0;
while (values.hasNext()) {
count += values.next();
}
emit (key, count);
}
It's exactly the same as the word count example, where, in your case, you have three words (categories): bad, normal, good.

failed to manipulate my Arraylist

I need help , I have an arrayList of objects . This object contains multiple fields I'm interested in this question by two date fields (date_panne date_mise and running) and two other time fields (heure_panne and time start),
And I would like to obtain the sum of the difference between (date_panne, heure_panne) and (date_mise_en_marche; heure_mise_en_marche) to give the total time of failure.
if someone can help me please I will be gratful this is my function :
public String disponibile() throws Exception {
int nbreArrets = 0;
List<Intervention> allInterventions = interventionDAO.fetchAllIntervention();
List<Intervention> listInterventions = new ArrayList<Intervention>();
for (Intervention currentIntervention : allInterventions) {
if (currentIntervention.getId_machine() == this.intervention.getId_machine()
&& currentIntervention.getDate_panne().compareTo(getProductionStartDate()) >= 0
&& currentIntervention.getDate_panne().compareTo(getProductionEndDate()) <= 0) {
listInterventions.add(currentIntervention);
}
}
savedInterventionList = listInterventions;
return "successView" ;
}
Assuming the the dates are truncated to the day and are of type java.util.Date, and that the times only contain hours, minutes, seconds and milliseconds and are also of type Date, start by creating a method like
private Date combine(Date dateOnly, Date timeOnly) {
Calendar dateCalendar = Calendar.getInstance();
dateCalendar.setTime(dateOnly);
Calendar timeCalendar = Calendar.getInstance();
timeCalendar.setTime(timeOnly);
dateCalendar.add(Calendar.HOUR_OF_DAY, timeCalendar.get(Calendar.HOUR_OF_DAY));
dateCalendar.add(Calendar.MINUTE, timeCalendar.get(Calendar.MINUTE));
dateCalendar.add(Calendar.SECOND, timeCalendar.get(Calendar.SECOND));
dateCalendar.add(Calendar.MILLISECOND, timeCalendar.get(Calendar.MILLISECOND));
return dateCalendar.getTime();
}
Now, it's simply a matter of looping through the interventions you want to sum, computing the difference between the dates as milliseconds, and add them:
long totalMillis = 0L;
for (Intervention intervention : interventions) {
Date marche = combine(intervention.getDateMiseEnMarche(), intervention.getTimeMiseEnMarche());
Date panne = combine(intervention.getDatePanne(), intervention.getTimePanne());
long differenceInMillis = marche.getTime() - panne.getTime();
totalMillis += differenceInMillis;
}

Resources