Simba Code:
program priceToExcel;
{$i srl-6/srl.simba}
const
theItem = 'Lobster'; // What item you want to grab prices for
amountOfPrices = 160; //160 is the max
var
scriptStartTime : String;
function RS_GetPricesOf(Item : String; numSamples: Int32 = 100): TIntegerArray;
var
i : Integer;
ID, Page, fullPage, RSpage, str, link: string;
items: TStringArray;
begin
item := Replace(item, ' ', '_', [rfReplaceAll]);
fullPage := GetPage('http://runescape.wikia.com/wiki/Exchange:' + Item);
ID := extractFromStr(between('"GEDBID">', '</span>', fullPage), Numbers);
link := 'http://services.runescape.com/m=itemdb_rs/'+ Item + '/viewitem.ws?obj=' + ID;
rsPage := getPage(link);
Items := MultiBetween(RSPage, 'average180.daily.push(',');');
if numSamples > Length(items) then
WriteLn(Format('[Hint] NumSamples overflow: Could only gather %d samples', [High(items)]));
for i := Max(High(items) - numSamples, 0) to High(items) do
Result.Append(strToInt(items[i]));
end;
procedure startTime;
var
Hour, Mins, Sec, MSec: Word;
Year, Month, Day : UInt16;
suffix : String;
begin
DecodeTime(Now, Hour, Mins, Sec, MSec);
DecodeDate(Now, Year, Month, Day);
if Hour < 12 then Suffix := 'AM' else Suffix := 'PM'
if Hour > 12 then Hour -= 12;
scriptStartTime := (' ' + toStr(Day) + '-' + toStr(Month) + '-' + toStr(Year) + ' at ' + Padz(IntToStr(Hour), 2) + Padz(IntToStr(Mins), 2) + Suffix);
end;
procedure WritetoFile(theArray : TIntegerArray; Item : String);
var
path, str, txt: String;
theFile, i, j : Integer;
begin
try
path := ScriptPath + Item + ' ';
theFile := RewriteFile(path + scriptStartTime + '.csv', False);
txt := 'Day:,';
for i := 0 to high(theArray)-1 do
txt := txt + toStr(i) + ',';
txt := txt + toStr(high(theArray));
txt := txt + [URL=https://villavu.com/forum/usertag.php?do=list&action=hash&hash=1]#1[/URL] 3[URL=https://villavu.com/forum/usertag.php?do=list&action=hash&hash=1]#1[/URL] 0 + Item + ',';
for i := 0 to high(theArray)-1 do
txt := txt + toStr(theArray[i]) + ',';
txt := txt + toStr(theArray[high(theArray)]);
WriteFileString(theFile, Txt);
CloseFile(theFile);
except
Writeln('Debug saving - error occurred');
end;
end;
begin
startTime();
WriteToFile(RS_GetPricesOf(theItem, amountofPrices), theItem);
end.
Simba Code:
program priceToExcel;
{$i srl-6/srl.simba}
const
theItem = 'Lobster'; // What item you want to grab prices for
amountOfPrices = 160; //160 is the max
MADays = 3;
RSIDays = 4;
StoKDays = 3;
StoDDays = 3;
AroonDays = 7;
BollDays = 6;
RSIUpper = 70;
RSILower = 30;
var
scriptStartTime : String;
Prices : TIntegerArray;
MAValue, RSIValue, StoKValue, StoDValue, AroonValue, BollUpper, BollLower : TExtendedArray;
MARec, RSIRec, StoRec, AroonRec, BollRec, TotalRec : TIntegerArray;
{----------------------------------------------------------------)
(function tIntegerArray.Slice )
(Returns a slice of the TIA between given indices (inclusive) )
(----------------------------------------------------------------}
function TIntegerArray.Slice(indexFrom, indexTo : Integer; Forwards : Boolean = True) : TIntegerArray;
var
i, x : Integer;
begin
if (high(self)) < indexTo then
begin
Writeln('TIntegerArray.Slice: Array high is ' + toStr(high(self)) + ', index ' + toStr(indexTo) + ' cannot be reached.');
Exit();
end;
Result := Copy(Self, indexFrom, (indexTo-indexFrom)+1);
if not Forwards then
result.invert();
end;
{----------------------------------------------------------------)
(function tExtendedArray.Slice )
(Returns a slice of the TIA between given indices (inclusive) )
(----------------------------------------------------------------}
function TExtendedArray.Slice(indexFrom, indexTo: Integer; Forwards : Boolean = True) : TExtendedArray;
var
i, x : Integer;
begin
if (length(self) - 1) < indexTo then
begin
Writeln('TIntegerArray.Slice: Array high is ' + toStr(high(self)) + ', index ' + toStr(indexTo) + ' cannot be reached.');
Exit();
end;
Result := Copy(Self, indexFrom, (indexTo-indexFrom)+1);
if not Forwards then
result.invert()
end;
{----------------------------------------------------------------)
(function tIntegerArray.Mean )
(Returns the mean of the given TIA )
(----------------------------------------------------------------}
function TIntegerArray.Mean() : Extended;
var
i, h, sum : Integer;
begin
h := high(Self);
for i := 0 to h do
sum += Self[i];
Result := sum/length(Self);
end;
{----------------------------------------------------------------)
(function tExtendedArray.Mean )
(Returns the mean of the given TEA )
(----------------------------------------------------------------}
function TExtendedArray.Mean() : Extended;
var
i, h : Integer;
sum : Extended;
begin
h := high(Self);
for i := 0 to h do
sum += Self[i];
Result := sum/length(Self);
end;
{----------------------------------------------------------------)
(function tIntegerArray.argMax )
(Returns the index which contains the highest value )
(----------------------------------------------------------------}
function TIntegerArray.argMax() : Integer;
var
i, h, tempInt : Integer;
begin
h := high(Self);
tempInt := self[0];
Result := 0;
for i := 0 to h do
if self[i] > tempInt then
begin
Result := i;
tempInt := Self[i];
end;
end;
{----------------------------------------------------------------)
(function tIntegerArray.argMin )
(Returns the index which contains the lowest value )
(----------------------------------------------------------------}
function TIntegerArray.argMin() : Integer;
var
i, h, tempInt : Integer;
begin
h := high(Self);
tempInt := self[0];
Result := 0;
for i := 0 to h do
if self[i] < tempInt then
begin
Result := i;
tempInt := Self[i];
end;
end;
{-------------------END TYPE FUNCTION SECTION--------------------)
(ALL CODE WRITTEN BELOW IS BY GARRETT UNLESS OTHERWISE INDICATED )
(----------------------------------------------------------------}
{----------------------------------------------------------------)
(TIntegerArray.StdDev() - Returns the Std Deviation of an array )
(Credit: SuperUser, Modified by Slacky )
(----------------------------------------------------------------}
function TIntegerArray.StdDev(): extended;
var
avg, total: extended;
i: integer;
begin
for i := 0 to High(self) do
total := total + self[i];
avg := total / Length(self);
total := 0;
for i := 0 to High(self) do
total := total + Sqr(self[i] - avg);
result := Sqrt(total / Length(self));
end;
procedure TBoolArray.Append(value:Boolean);
begin
Self := Self + value;
end;
procedure RS_GetPricesOf(Item : String; numSamples: Int32 = 100);
var
i : Integer;
ID, Page, fullPage, RSpage, str, link: string;
items: TStringArray;
begin
item := Replace(item, ' ', '_', [rfReplaceAll]);
fullPage := GetPage('http://runescape.wikia.com/wiki/Exchange:' + Item);
ID := extractFromStr(between('"GEDBID">', '</span>', fullPage), Numbers);
link := 'http://services.runescape.com/m=itemdb_rs/'+ Item + '/viewitem.ws?obj=' + ID;
rsPage := getPage(link);
Items := MultiBetween(RSPage, 'average180.daily.push(',');');
if numSamples > Length(items) then
WriteLn(Format('[Hint] NumSamples overflow: Could only gather %d samples', [High(items)]));
for i := Max(High(items) - numSamples, 0) to High(items) do
//Prices[i] := (strToInt(items[i]));
Prices.append(strToInt(items[i]));
end;
{-----------------------------------------------------------------)
(function doMA )
(Determines the Moving Average Score )
(-----------------------------------------------------------------}
procedure doMA();
var
i, h: Integer;
avg, comp: Extended;
tempA: TIntegerArray;
begin
for i := 0 to MADays - 2 do
MARec[i] := 0; // You need at least 2 days to get data
h := high(Prices); // Defined when we grab prices - we want the same amount of calculations as there are prices
for i := MADays - 1 to h do //For the rest of the prices, figure out the MA
begin
tempA := Prices.slice(i - (MADays - 1), i); // This creates a temporary array from a slice of the price array
avg := TempA.Mean(); // Grab the average of the values in the temporary slice
comp := avg - Prices[i]; // The comparison here is between the average and the current day's price
MAValue[i] := avg;
if comp > 0 then // If the average is higher than today's prices (we're in a down trend), so rec is -1 (Sell)
MARec[i] := -1
else if comp = 0 then // If the average is the same as today's prices there is no new recommendation (Hold)
MARec[i] := 0
else
MARec[i] := 1; // If the average is below today's prices (we're in an uptrend), the rec is 1 (Buy)
end;
end;
{-----------------------------------------------------------------)
(function doRSI )
(Determines the Relative Strength Index (RSI) Score )
(-----------------------------------------------------------------}
procedure doRSI();
var
i, h, change : Integer;
Gains, Losses, tempG, tempL : TIntegerArray;
avgG, avgL, RSI: Extended;
begin
h := high(Prices); // Defined when we grab prices - we want the same amount of calculations as there are prices
SetLength(Gains, h+1);
SetLength(Losses, h+1);
Gains[0] := 0; // The first day you can't take a comparison of gain or loss, set both to 0
Losses[0] := 0;
for i := 1 to h do // You can do comparision from day 1 (second day) to the last day, do comparisons
begin
Change := (Prices[i] - Prices[i-1]); // The change from Day[i-1] to Day[i]
if Change > 0 then Gains[i] := Change else Gains[i] := 0; //If change is positive, add it to gains (else gains is 0)
if Change < 0 then Losses[i] := (0-Change) else Losses[i] := 0; //If change is negative, add it to losses (else losses is 0)
end;
for i := 0 to RSIDays - 2 do // This is where we start assigning scores
RSIRec[i] := 0; // Can't have scores for the first (RSIDays - 2) Days (not enough data points)
for i := RSIDays - 1 to h do
begin
tempG := Gains.Slice(i - (RSIDays - 1) , i); // The temporary gains and losses arrays are generated for processing
tempL := Losses.Slice(i - (RSIDays - 1), i);
avgG := tempG.Mean(); //Take the average of each slice
avgL := tempL.Mean();
if avgL = 0 then // This saves us from dividing by 0, the RSI Score is set to 100
RSIValue[i] := 100
else
RSIValue[i] := 100 - (100 / (1 + (avgG/avGL))); // This is the main calculation after the above processing
if (RSIValue[i-1] > RSIUpper) and (RSIValue[i] < RSIUpper) then RSIRec[i] := -1 // If we cross from above overbought to below, that's a sell signal
else if (RSIValue[i-1] < RSILower) and (RSIValue[i] > RSILower) then RSIRec[i] := 1 // If we cross from below oversold to above, buy signal
else RSIRec[i] := 0; // If neither of those options, no rec (Hold)
end;
end;
{-----------------------------------------------------------------)
(function doStoch )
(Uses Stochastic Oscillator to determine if Over or Under Bought )
(-----------------------------------------------------------------}
procedure doStoch();
var
i, h : Integer;
minP, maxP: Integer;
d: Extended;
k: TExtendedArray;
tempA : TIntegerArray;
begin
h := high(Prices); // Defined when we grab prices - we want the same amount of calculations as there are prices
for i := 0 to (StoKDays + StoDDays) - 3 do // It works out that we can't have recs for this range
StoRec[i] := 0;
for i := 0 to StoKDays - 2 do // There can be no K values for this range
StoKValue[i] := 0;
for i := (StoKDays - 1) to h do // Generate the k values
begin
tempA := Prices.Slice(i - (StoKDays - 1), i); // Generate our temporary range
minP := MinA(tempA); // Gets the lowest value (price)
maxP := MaxA(tempA); // Gets the highest value (price)
if (maxP - minP) <= 0 then // Saves us from divide by 0 errors
StoKValue[i] := 100 // Maximum k is 100
else
StoKValue[i] := 100 * ((tempA[high(tempA)] - minP) / (maxP - minP)); // The actual formula for the k values
end;
for i := (StoKDays + StoDDays - 2) to h do
begin
StoDValue[i] := StoKValue.Slice(i - (stoDDays - 1), i).Mean(); // Takes the moving average of k values
if StoDValue[i] > StoKValue[i] then // If current k value is under moving average (going below the average), sell
StoRec[i] := -1
else if StoDValue[i] < StoKValue[i] then // If current k value is over moving average (going above the average), buy
StoRec[i] := 1
else
StoRec[i] := 0;
end;
end;
{-----------------------------------------------------------------)
(function doAroon )
(Determines the Aroon Indicator Score )
(-----------------------------------------------------------------}
procedure doAroon();
var
i, h, maxDay, minDay: Integer;
upDir, downDir, Aroon: Extended;
tempA: TIntegerArray;
begin
h := high(Prices); // Defined when we grab prices - we want the same amount of calculations as there are prices
for i := 0 to AroonDays - 2 do
AroonRec[i] := 0;
for i := AroonDays - 1 to h do
begin
tempA := Prices.Slice(i - (AroonDays - 1), i, False); //Reverse so that newest days are 0 and increasing, so high today gives 0 as index (0 days since high)
maxDay := tempA.argMax(); //Gets the index of the maximum price (days since high price) in the slice
minDay := tempA.argMin(); //Gets the index for the low price (days since low price) in the slice
upDir := 100 * (((AroonDays - 1) - MaxDay) / (AroonDays - 1)); // The Aroon Up score
downDir := 100 * (((AroonDays - 1) - MinDay) / (AroonDays - 1)); // The Aroon Down score
AroonValue[i] := upDir - downDir; // Gives the overall Aroon score
if upDir > downDir then // If we are net-positive score (uptrend) then buy
AroonRec[i] := 1
else if upDir < downDir then // If we are net-negative score (downtrend) then sell
AroonRec[i] := -1
else
AroonRec[i] := 0; // If the score is 0 then no rec (hold)
end;
end;
{-----------------------------------------------------------------)
(function doBollinger )
(Defines the Bollinger Bands and predicts trends )
(-----------------------------------------------------------------}
procedure doBollinger();
var
i, h : Integer;
tempA: TIntegerArray;
avg, SD, SDMult: Extended;
touchUpper, touchLower: TBoolArray;
begin
h := high(Prices); // Defined when we grab prices - we want the same amount of calculations as there are prices
SetLength(touchUpper, h + 1);
SetLength(touchLower, h + 1);
for i := 0 to BollDays - 2 do
begin
BollRec[i] := 0;
BollUpper[i] := 0;
BollLower[i] := 0;
touchUpper[i] := False;
touchLower[i] := False;
end;
for i := BollDays - 1 to h do
begin
tempA := Prices.Slice(i - (BollDays - 1), i); // Grabs our temporary array
avg := tempA.Mean(); // Takes the average
SD := tempA.StdDev(); // Takes the standard deviation
BollUpper[i] := (Avg + (SD * 1.9)); // This calculates the upper band
BollLower[i] := (Avg - (SD * 1.9)); // This calculates the lower band
touchUpper[i] := (Prices[i] >= (BollUpper[i] * (1 - (1 / 100)))); // Are we touching the upper band? Within 1%
touchLower[i] := (Prices[i] <= (BollLower[i] * (1 + (1 / 100)))); // Are we touching the lower band? Within 1%
end;
for i := BollDays - 1 to h do
begin
if touchLower[i-1] and (not touchLower[i]) then // If we were touching lower and aren't anymore, buy signal
BollRec[i] := 1
else if touchUpper[i-1] and (not touchUpper[i]) then // If we were touching upper and aren't anymore, sell signal
BollRec[i] := -1
else
BollRec[i] := (0);
end;
end;
{-----------------------------------------------------------------)
(function totalScore )
(Totals the score from the above 5 algorithms )
(-----------------------------------------------------------------}
procedure TotalScore();
var
i, h : Integer;
begin
h := high(Prices); // Defined when we grab prices - we want the same amount of calculations as there are prices
for i := 0 to h do
TotalRec[i] := (MARec[i] + RSIRec[i] + StoRec[i] + AroonRec[i] + BollRec[i]);
end;
procedure Setup();
begin
SetLength(MAValue, AmountofPrices + 1);
SetLength(RSIValue, AmountofPrices + 1);
SetLength(StoKValue, AmountofPrices + 1);
SetLength(StoDValue, AmountofPrices + 1);
SetLength(AroonValue, AmountofPrices + 1);
SetLength(BollUpper, AmountofPrices + 1);
SetLength(BollLower, AmountofPrices + 1);
SetLength(MARec, AmountofPrices + 1);
SetLength(RSIRec, AmountofPrices + 1);
SetLength(StoRec, AmountofPrices + 1);
SetLength(AroonRec, AmountofPrices + 1);
SetLength(BollRec, AmountofPrices + 1);
SetLength(TotalRec, AmountofPrices + 1);
end;
procedure startTime;
var
Hour, Mins, Sec, MSec: Word;
Year, Month, Day : UInt16;
suffix : String;
begin
DecodeTime(Now, Hour, Mins, Sec, MSec);
DecodeDate(Now, Year, Month, Day);
if Hour < 12 then Suffix := 'AM' else Suffix := 'PM'
if Hour > 12 then Hour -= 12;
scriptStartTime := (' ' + toStr(Day) + '-' + toStr(Month) + '-' + toStr(Year) + ' at ' + Padz(IntToStr(Hour), 2) + Padz(IntToStr(Mins), 2) + Suffix);
end;
procedure WritetoFile();
var
path, str, txt: String;
theFile, i, j : Integer;
begin
try
path := ScriptPath + theItem + ' ';
theFile := RewriteFile(path + scriptStartTime + '.csv', False);
txt := 'Day:,';
for i := 0 to high(Prices)-1 do
txt := txt + toStr(i) + ',';
txt := txt + toStr(high(Prices));
txt := txt + [URL=https://villavu.com/forum/usertag.php?do=list&action=hash&hash=1]#1[/URL] 3[URL=https://villavu.com/forum/usertag.php?do=list&action=hash&hash=1]#1[/URL] 0 + theItem + ','; // Writes Prices
for i := 0 to high(Prices)-1 do
txt := txt + toStr(Prices[i]) + ',';
txt := txt + toStr(Prices[high(Prices)]);
txt := txt + [URL=https://villavu.com/forum/usertag.php?do=list&action=hash&hash=1]#1[/URL] 3[URL=https://villavu.com/forum/usertag.php?do=list&action=hash&hash=1]#1[/URL] 0 + 'MAValue,';
for i := 0 to high(MAValue)-1 do
txt := txt + toStr(MAValue[i]) + ',';
txt := txt + toStr(MAValue[high(Prices)]);
txt := txt + [URL=https://villavu.com/forum/usertag.php?do=list&action=hash&hash=1]#1[/URL] 3[URL=https://villavu.com/forum/usertag.php?do=list&action=hash&hash=1]#1[/URL] 0 + 'MARec,';
for i := 0 to high(MARec)-1 do
txt := txt + toStr(MARec[i]) + ',';
txt := txt + toStr(MARec[high(Prices)]);
txt := txt + [URL=https://villavu.com/forum/usertag.php?do=list&action=hash&hash=1]#1[/URL] 3[URL=https://villavu.com/forum/usertag.php?do=list&action=hash&hash=1]#1[/URL] 0 + 'RSIValue,';
for i := 0 to high(RSIValue)-1 do
txt := txt + toStr(RSIValue[i]) + ',';
txt := txt + toStr(RSIValue[high(Prices)]);
txt := txt + [URL=https://villavu.com/forum/usertag.php?do=list&action=hash&hash=1]#1[/URL] 3[URL=https://villavu.com/forum/usertag.php?do=list&action=hash&hash=1]#1[/URL] 0 + 'RSIRec,';
for i := 0 to high(RSIRec)-1 do
txt := txt + toStr(RSIRec[i]) + ',';
txt := txt + toStr(RSIRec[high(Prices)]);
txt := txt + [URL=https://villavu.com/forum/usertag.php?do=list&action=hash&hash=1]#1[/URL] 3[URL=https://villavu.com/forum/usertag.php?do=list&action=hash&hash=1]#1[/URL] 0 + 'StoKValue,';
for i := 0 to high(StoKValue)-1 do
txt := txt + toStr(StoKValue[i]) + ',';
txt := txt + toStr(StoKValue[high(Prices)]);
txt := txt + [URL=https://villavu.com/forum/usertag.php?do=list&action=hash&hash=1]#1[/URL] 3[URL=https://villavu.com/forum/usertag.php?do=list&action=hash&hash=1]#1[/URL] 0 + 'StoDValue,';
for i := 0 to high(StoDValue)-1 do
txt := txt + toStr(StoDValue[i]) + ',';
txt := txt + toStr(StoDValue[high(Prices)]);
txt := txt + [URL=https://villavu.com/forum/usertag.php?do=list&action=hash&hash=1]#1[/URL] 3[URL=https://villavu.com/forum/usertag.php?do=list&action=hash&hash=1]#1[/URL] 0 + 'StoRec,';
for i := 0 to high(StoRec)-1 do
txt := txt + toStr(StoRec[i]) + ',';
txt := txt + toStr(StoRec[high(Prices)]);
txt := txt + [URL=https://villavu.com/forum/usertag.php?do=list&action=hash&hash=1]#1[/URL] 3[URL=https://villavu.com/forum/usertag.php?do=list&action=hash&hash=1]#1[/URL] 0 + 'AroonValue,';
for i := 0 to high(AroonValue)-1 do
txt := txt + toStr(AroonValue[i]) + ',';
txt := txt + toStr(AroonValue[high(Prices)]);
txt := txt + [URL=https://villavu.com/forum/usertag.php?do=list&action=hash&hash=1]#1[/URL] 3[URL=https://villavu.com/forum/usertag.php?do=list&action=hash&hash=1]#1[/URL] 0 + 'AroonRec,';
for i := 0 to high(AroonRec)-1 do
txt := txt + toStr(AroonRec[i]) + ',';
txt := txt + toStr(AroonRec[high(Prices)]);
txt := txt + [URL=https://villavu.com/forum/usertag.php?do=list&action=hash&hash=1]#1[/URL] 3[URL=https://villavu.com/forum/usertag.php?do=list&action=hash&hash=1]#1[/URL] 0 + 'BollUpper,';
for i := 0 to high(BollUpper)-1 do
txt := txt + toStr(BollUpper[i]) + ',';
txt := txt + toStr(BollUpper[high(Prices)]);
txt := txt + [URL=https://villavu.com/forum/usertag.php?do=list&action=hash&hash=1]#1[/URL] 3[URL=https://villavu.com/forum/usertag.php?do=list&action=hash&hash=1]#1[/URL] 0 + 'BollLower,';
for i := 0 to high(BollLower)-1 do
txt := txt + toStr(BollLower[i]) + ',';
txt := txt + toStr(BollLower[high(Prices)]);
txt := txt + [URL=https://villavu.com/forum/usertag.php?do=list&action=hash&hash=1]#1[/URL] 3[URL=https://villavu.com/forum/usertag.php?do=list&action=hash&hash=1]#1[/URL] 0 + 'BollRec,';
for i := 0 to high(BollRec)-1 do
txt := txt + toStr(BollRec[i]) + ',';
txt := txt + toStr(BollRec[high(Prices)]);
txt := txt + [URL=https://villavu.com/forum/usertag.php?do=list&action=hash&hash=1]#1[/URL] 3[URL=https://villavu.com/forum/usertag.php?do=list&action=hash&hash=1]#1[/URL] 0 + 'TotalRec,';
for i := 0 to high(TotalRec)-1 do
txt := txt + toStr(TotalRec[i]) + ',';
txt := txt + toStr(TotalRec[high(Prices)]);
WriteFileString(theFile, Txt);
CloseFile(theFile);
except
Writeln('Debug saving - error occurred');
end;
end;
begin
startTime();
Setup();
RS_GetPricesOf(theItem, amountofPrices);
doMA();
doRSI();
doStoch();
doAroon();
doBollinger();
totalScore();
writetoFile();
end.