Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- program Mercher;
- {$I SimbaExt/SimbaExt.simba}
- const
- {Only Required for First-Time Run or backchecking}
- startCash = 1000000;
- {BackCheck Settings - Only required if testing algorithm settings}
- backCheck = False;
- simDays = 100;
- {Algorithm Settings - Experimentally Determined - Changes allowed if you know what they do}
- ScoreRange = 3;
- MACDDays = 3;
- RSIDays = 3;
- StoDays1 = 3;
- StoDays2 = 3;
- AroonDays = 3;
- BollDays = 4;
- PickDays = 15;
- PickPercent = 5;
- BuyPercentage = 25;
- {Do NOT Touch Below Here}
- ALGO_BUY = 1;
- ALGO_HOLD = 0;
- ALGO_SELL = - 1;
- type
- TItemInfo = record
- Prices, MACDScore, RSIScore, StoScore, ArScore, BolScore, TotScore: TIntArray;
- Name: string;
- TradeLimit, AmountOwned, Bought, GoodTrades, Trades: Integer;
- end;
- TItemInfoArray = array of TItemInfo;
- type
- TPortfolio = record
- Items: TItemInfoArray;
- Cash: Integer;
- end;
- function pickItems(currentDay, range, limitFrac: Integer; theItem: TItemInfo): Integer;
- var
- i, h, MinP, MaxP: Integer;
- avg, Score: Extended;
- tempA: TIntArray;
- begin
- Result := ALGO_BUY;
- if currentDay - (range - 1) < 0 then
- Exit;
- setLength(tempA, range);
- tempA := theItem.Prices.Slice(currentDay - (range - 1), currentDay);
- se.MinMaxTIA(tempA, MinP, MaxP);
- avg := tempA.Mean();
- Score := (MaxP - MinP) / Avg;
- if Score < (limitFrac / 100) then
- Result := ALGO_SELL;
- end;
- function MACD(currentDay, range: Integer; theItem: TItemInfo): Integer;
- var
- i, h, x, y: Int32;
- avg, comp: Extended;
- tempA: TIntegerArray;
- begin
- if (range - 1) > currentDay then
- begin
- Result := ALGO_HOLD;
- Exit;
- end;
- setLength(tempA, range);
- tempA := theItem.Prices.slice(currentDay - (range - 1), currentDay);
- avg := TempA.mean();
- comp := avg - theItem.Prices[currentDay];
- if comp > 0 then
- Result := ALGO_SELL;
- if comp = 0 then
- Result := ALGO_HOLD;
- if comp < 0 then
- Result := ALGO_BUY;
- end;
- function doRSI(currentDay, range, Upper, Lower: Integer; theItem: TItemInfo): Integer;
- var
- i, h, x, change, y: Integer;
- Gains, Losses : TIntegerArray;
- avgG, avgL, RS, RSI: Extended;
- begin
- if (range - 2) > currentDay then
- begin
- Result := ALGO_HOLD;
- Exit;
- end;
- SetLength(Gains, range);
- SetLength(Losses, range);
- x := (currentDay - (range - 1));
- for i := (currentDay - (range - 1)) to currentDay do
- begin
- change := theItem.Prices[i] - theItem.Prices[i - 1];
- if change > 0 then
- begin
- Gains[i - x] := change;
- Losses[i - x] := 0;
- end
- else if change < 0 then
- begin
- Losses[i - x] := 0 - change;
- Gains[i - x] := 0;
- end;
- end;
- avgG := Gains.mean();
- avgL := Losses.mean();
- if avgL = 0 then
- RSI := 100
- else
- begin
- RS := avgG / avgL;
- RSI := 100 - (100 / (1 + RS))
- end;
- if RSI > Upper then
- Result := ALGO_SELL
- else if RSI < Lower then
- Result := ALGO_BUY
- else
- Result := ALGO_HOLD;
- end;
- function doSto(currentDay, range1, range2: Integer; theItem: TItemInfo): Integer;
- var
- i, h, x: Integer;
- minP, maxP: Integer;
- d: Extended;
- k: TExtArray;
- tempA: TIntArray;
- begin
- if (currentDay - (range1 - 1) - (range2 - 1)) < 0 then
- begin
- Result := ALGO_HOLD;
- Exit;
- end;
- setLength(k, range2);
- setLength(tempA, range1);
- x := currentDay - (range2 - 1);
- for i := (currentDay - (range2 - 1)) to currentDay do
- begin
- tempA := theItem.Prices.slice(i - (range1 - 1), i);
- se.MinMaxTIA(tempA, minP, maxP);
- if (maxP - minP) <= 0 then
- k[i - x] := 100
- else
- k[i - x] := 100 * ((tempA[high(tempA)] - minP) / (maxP - minP));
- end;
- d := K.mean();
- h := high(k);
- if d > k[h] then
- Result := ALGO_SELL;
- if d < k[h] then
- Result := ALGO_BUY;
- if d = k[h] then
- Result := ALGO_HOLD;
- end;
- function doAroon(currentDay, range: Integer; theItem: TItemInfo): Integer;
- var
- i, h, y, x, maxDay, minDay: Integer;
- upDir, downDir, Aroon: Extended;
- tempA: TIntegerArray;
- begin
- if currentDay - (range - 1) < 0 then
- begin
- Result := ALGO_HOLD;
- Exit;
- end;
- SetLength(tempA, range);
- tempA := theItem.Prices.Slice(currentDay, currentDay - (range - 1), - 1);
- maxDay := TempA.argMax();
- minDay := TempA.argMin();
- upDir := 100 * (((range - 1) - MaxDay) / (range - 1));
- downDir := 100 * (((range - 1) - MinDay) / (range - 1));
- Aroon := upDir - downDir;
- if Aroon > 0 then
- Result := ALGO_BUY;
- if Aroon < 0 then
- Result := ALGO_SELL;
- if Aroon = 0 then
- Result := ALGO_HOLD;
- end;
- function Bollinger(currentDay, range, percentClose: Integer; SDMultiplier: Extended; theItem: TItemInfo): Integer;
- var
- i, h, x: Integer;
- tempA: TIntArray;
- avg, SD, SDMult: Extended;
- upper, lower: TExtArray;
- touchUpper, touchLower: array of Boolean;
- begin
- if currentDay - range < 0 then
- begin
- Result := ALGO_HOLD;
- Exit;
- end;
- SetLength(Upper, 2);
- SetLength(Lower, 2);
- SetLength(TouchUpper, 2);
- SetLength(TouchLower, 2);
- SetLength(tempA, range);
- x := 0;
- for i := 1 downto 0 do
- begin
- tempA := theItem.Prices.slice(currentDay - i - (range - 1), currentDay - i);
- avg := tempA.Mean();
- SD := tempA.Stdev();
- SDMult := SD * SDMultiplier;
- Upper[x] := avg + SDMult;
- Lower[x] := avg - SDMult;
- touchUpper[x] := (theItem.Prices[currentDay - i] >= (Upper[x] * (1 - (percentClose / 100))));
- touchLower[x] := (theItem.Prices[currentDay - i] <= (Lower[x] * (1 + (percentClose / 100))));
- inc(x);
- end;
- if (touchLower[0] and (not touchLower[1])) then
- begin
- Result := ALGO_BUY;
- Exit;
- end;
- if (touchUpper[0] and (not touchUpper[1])) then
- begin
- Result := ALGO_SELL;
- Exit;
- end;
- Result := ALGO_HOLD;
- end;
- function addResults(currentDay: Integer; theItem: TItemInfo): Integer;
- begin
- Result := theItem.MACDScore[currentDay] + theItem.RSIScore[currentDay] + theItem.StoScore[currentDay] + theItem.ArScore[currentDay] + theItem.BolScore[currentDay];
- end;
- function ScoreItems(currentDay, range: Integer; totalScores : TIntArray): Integer;
- var
- tempScore: TIntArray;
- begin
- setLength(tempScore, range);
- tempScore := TotalScores.Slice(currentDay - (range - 1), currentDay);
- Result := se.SumTIA(tempScore);
- end;
- procedure handleBuys(var Portfolio: TPortfolio; currentDay, percentBuy: Integer);
- var
- i, h, toBuy, inventory, startCash, theScore: Integer;
- purchased: Boolean;
- begin
- h := high(portfolio.Items);
- startCash := Portfolio.Cash;
- for i := 0 to h do
- begin
- if (ScoreRange > 0) and (currentDay - (scoreRange - 1) >= 0) then
- theScore := ScoreItems(currentDay, scoreRange, Portfolio.Items[i].totScore)
- else
- theScore := 1;
- if (Portfolio.Items[i].TotScore[CurrentDay] > ALGO_HOLD) and (Portfolio.Items[i].AmountOwned = 0) and (theScore >= 0) then
- begin
- toBuy := trunc((startCash * (percentBuy / 100)) / Portfolio.Items[i].Prices[currentDay]);
- if toBuy > Portfolio.Items[i].TradeLimit then
- toBuy := Portfolio.Items[i].TradeLimit;
- if toBuy * Portfolio.Items[i].Prices[currentDay] > Portfolio.Cash then
- toBuy := trunc(Portfolio.Cash / Portfolio.Items[i].Prices[currentDay]);
- Portfolio.Items[i].AmountOwned := toBuy;
- Portfolio.Cash := Portfolio.Cash - (toBuy * Portfolio.Items[i].Prices[currentDay]);
- Portfolio.Items[i].Bought := Portfolio.Items[i].Prices[currentDay];
- end;
- if ((Portfolio.Items[i].TotScore[CurrentDay] < ALGO_HOLD) and (Portfolio.Items[i].AmountOwned > 0)) or (currentDay = simDays) then
- begin
- Portfolio.Cash := Portfolio.Cash + (Portfolio.Items[i].AmountOwned * Portfolio.Items[i].Prices[currentDay]);
- Portfolio.Items[i].AmountOwned := 0;
- inc(Portfolio.Items[i].Trades);
- if Portfolio.Items[i].Prices[currentDay] >= Portfolio.Items[i].Bought then
- inc(Portfolio.Items[i].GoodTrades);
- Portfolio.Items[i].Bought := 0;
- end;
- end;
- end;
- function RS_GetPricesOf(Item: string; numSamples: Int32 = 100): TItemInfo;
- var
- i, date, value, exchangeLim: Int32;
- Page, fullPage, str: string;
- items, list: TStringArray;
- function FindPriceList(const text: string): string;
- var
- p: Integer;
- begin
- p := pos('<p class="GEdataprices"', text);
- result := copy(text, p, length(text) - p);
- end;
- begin
- item := Replace(item, ' ', '_', [rfReplaceAll]);
- fullPage := GetPage('http://runescape.wikia.com/wiki/Exchange:' + Item);
- page := FindPriceList(fullPage);
- Result.TradeLimit := StrtoInt(Between('data-limit="', '" style="display:none">', Page));
- Result.Name := Item;
- items := Explode(',', Between('>', '</p>', page));
- 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
- begin
- list := Explode(':', items[i]);
- if length(list) >= 2 then
- begin
- value := list[1].GetNumbers()[0];
- Result.Prices.Append(value);
- end;
- end;
- end;
- function RS_GetTopItems100(): TStringArray;
- var
- i: Int32;
- Str: string;
- function ForwardStrTo(const text, tag: string; After: Boolean = False): string;
- var
- p: Integer;
- begin
- p := pos(tag, text);
- if After then
- Result := copy(text, p + length(tag), length(text) - p - length(tag) + 1)
- else
- Result := copy(text, p, length(text) - p);
- end;
- begin
- Str := GetPage('http://services.runescape.com/m=itemdb_rs/top100?list=0&scale=2');
- Str := Between('<th colspan="4">Trade Count</th>', '</tbody>', Str);
- Str := ForwardStrTo(Str, '<tbody>');
- Result := MultiBetween(str, '<img src="http://services.runescape.com/', '">');
- for i := 0 to High(Result) do
- begin
- Result[i] := ForwardStrTo(Result[i], 'alt="', True);
- end;
- end;
- procedure SetupINIFile;
- var
- firstRun: Boolean;
- Strings: TStringArray;
- i: Integer;
- begin
- firstRun := (messageBox('Is this your first time running this script?', 'Setup', 4) = 6);
- if firstRun then
- begin
- SetLength(Strings, 100);
- Strings := RS_GetTopItems100();
- WriteINI('Portfolio', 'Cash', toStr(StartCash), ScriptPath + 'MerchantSettings');
- WriteINI('Portfolio', 'Item Length', toStr(length(Strings)), ScriptPath + 'MerchantSettings');
- for i := 0 to high(Strings) do
- begin
- WriteINI('Portfolio', toStr(i), Strings[i], ScriptPath + 'MerchantSettings');
- WriteINI(Strings[i], 'Bought', '0', ScriptPath + 'MerchantSettings');
- WriteINI(Strings[i], 'Amount', '0', ScriptPath + 'MerchantSettings');
- end;
- end;
- end;
- function INIGetStrings() : TStringArray;
- var
- i, h: Integer;
- begin
- //SetLength(Result, strToInt(ReadINI('Portfolio', 'Item Length', ScriptPath + 'MerchantSettings')));
- h := strToInt(ReadINI('Portfolio', 'Item Length', ScriptPath + 'MerchantSettings'));
- for i := 0 to h-1 do
- Result.Append(ReadINI('Portfolio', toStr(i), ScriptPath + 'MerchantSettings'));
- end;
- function INIGetCash() : Integer;
- begin
- Result := strToInt(ReadINI('Portfolio', 'Cash', ScriptPath + 'MerchantSettings'));
- end;
- procedure doRecommend(thePortfolio: TPortfolio; day, percentBuy: Integer);
- var
- i, h, toBuy, inventory, theScore, cashStart: Integer;
- purchased: Boolean;
- TTIA : TIntArray;
- begin
- h := high(thePortfolio.Items);
- CashStart := thePortfolio.Cash;
- for i := 0 to h do
- begin
- //writeln('Item: ' + toStr(theportfolio.Items[i]));
- //Writeln('Day: ' + toStr(Day) + ', High Prices: ' + toStr(high(thePortfolio.Items[i].Prices)));
- TTIA := thePortfolio.Items[i].TotScore;
- theScore := ScoreItems(Day, scoreRange, TTIA);
- if (thePortfolio.Items[i].TotScore[day] > ALGO_HOLD) and (thePortfolio.Items[i].AmountOwned = 0) and (theScore >= 0) then
- begin
- toBuy := trunc((CashStart * (percentBuy / 100)) / thePortfolio.Items[i].Prices[Day]);
- if toBuy > thePortfolio.Items[i].TradeLimit then
- toBuy := thePortfolio.Items[i].TradeLimit;
- if toBuy * thePortfolio.Items[i].Prices[Day] > thePortfolio.Cash then
- toBuy := trunc(thePortfolio.Cash / thePortfolio.Items[i].Prices[Day]);
- if toBuy = 0 then continue;
- if (messageBox('Would you like to buy ' + toStr(toBuy) + ' ' + thePortfolio.Items[i].Name + ' for ' + toStr(thePortfolio.Items[i].Prices[day]) + 'gp each, a total of ' + tostr(toBuy * thePortfolio.Items[i].Prices[Day]) + '?', 'Buy?', 4) = 6) then
- begin
- thePortfolio.Items[i].AmountOwned := toBuy;
- thePortfolio.Cash := thePortfolio.Cash - (toBuy * thePortfolio.Items[i].Prices[Day]);
- thePortfolio.Items[i].Bought := thePortfolio.Items[i].Prices[Day];
- WriteINI(thePortfolio.Items[i].Name, 'Amount', toStr(toBuy), ScriptPath + 'MerchantSettings');
- WriteINI(thePortfolio.Items[i].Name, 'Bought', toStr(thePortfolio.Items[i].Prices[Day]), ScriptPath + 'MerchantSettings');
- end;
- end;
- if ((thePortfolio.Items[i].TotScore[Day] < ALGO_HOLD) and (thePortfolio.Items[i].AmountOwned > 0)) then
- begin
- if (messageBox('Would you like to sell ' + toStr(toBuy) + ' ' + thePortfolio.Items[i].Name + ' for ' + toStr(thePortfolio.Items[i].Prices[day]) + 'gp each, a total of ' + tostr(thePortfolio.Items[i].AmountOwned * thePortfolio.Items[i].Prices[Day]) + '?', 'Sell?', 4) = 6) then
- begin
- thePortfolio.Cash := thePortfolio.Cash + (thePortfolio.Items[i].AmountOwned * thePortfolio.Items[i].Prices[Day]);
- thePortfolio.Items[i].AmountOwned := 0;
- inc(thePortfolio.Items[i].Trades);
- if thePortfolio.Items[i].Prices[Day] >= thePortfolio.Items[i].Bought then
- inc(thePortfolio.Items[i].GoodTrades);
- thePortfolio.Items[i].Bought := 0;
- WriteINI(thePortfolio.Items[i].Name, 'Amount', '0', ScriptPath + 'MerchantSettings');
- WriteINI(thePortfolio.Items[i].Name, 'Bought', '0', ScriptPath + 'MerchantSettings');
- end;
- end;
- end;
- WriteINI('Portfolio', 'Cash', toStr(thePortfolio.Cash), ScriptPath + 'MerchantSettings');
- end;
- var
- Strings: TStringArray;
- i, j, days, res: Integer;
- myPortfolio, tempPort: TPortfolio;
- begin
- ClearDebug();
- if not BackCheck then SetupINIFile();
- if BackCheck then Strings := RS_GetTopItems100() else Strings := INIGetStrings();
- if BackCheck then Days := simDays else Days := 30;
- if BackCheck then myPortfolio.Cash := startCash else myPortfolio.Cash := INIGetCash();
- SetLength(myPortfolio.Items, Length(Strings));
- Writeln('Getting Prices: Be Patient');
- for i := 0 to high(Strings) do
- begin
- myPortfolio.Items[i] := RS_GetPricesOf(Strings[i], Days);
- if not Backcheck then
- begin
- myPortfolio.Items[i].Name := Replace(myPortfolio.Items[i].Name, '_', ' ', [rfReplaceAll]);
- myPortfolio.Items[i].AmountOwned := strToInt(ReadINI(myPortfolio.Items[i].Name, 'Amount', ScriptPath + 'MerchantSettings'));
- myPortfolio.Items[i].Bought := strToInt(ReadINI(myPortfolio.Items[i].Name, 'Bought', ScriptPath + 'MerchantSettings'));
- end;
- //myPortfolio.Items[i].GoodTrades :=
- //myPortfolio.Items[i].Trades :=
- end;
- for j := 0 to high(myPortfolio.Items) do
- begin
- if myPortfolio.Items[j].Name = '' then Continue;
- setLength(myPortfolio.Items[j].MACDScore, Days + 1);
- setLength(myPortfolio.Items[j].RSIScore, Days + 1);
- setLength(myPortfolio.Items[j].StoScore, Days + 1);
- setLength(myPortfolio.Items[j].ArScore, Days + 1);
- setLength(myPortfolio.Items[j].BolScore, Days + 1);
- setLength(myPortfolio.Items[j].TotScore, Days + 1);
- for i := 0 to Days do
- begin
- if pickItems(i, PickDays, PickPercent, myPortfolio.Items[j]) > ALGO_HOLD then
- begin
- myPortfolio.Items[j].MACDScore[i] := MACD(i, MACDDays, myPortfolio.Items[j]);
- myPortfolio.Items[j].RSIScore[i] := doRSI(i, RSIDays, 70, 30, myPortfolio.Items[j]);
- myPortfolio.Items[j].StoScore[i] := doSto(i, StoDays1, StoDays2, myPortfolio.Items[j]);
- myPortfolio.Items[j].ArScore[i] := doAroon(i, AroonDays, myPortfolio.Items[j]);
- myPortfolio.Items[j].BolScore[i] := Bollinger(i, BollDays, 1, 1.9, myPortfolio.Items[j]);
- myPortfolio.Items[j].TotScore[i] := addResults(i, myPortfolio.Items[j]);
- end else
- begin
- myPortfolio.Items[j].MACDScore[i] := 0;
- myPortfolio.Items[j].RSIScore[i] := 0;
- myPortfolio.Items[j].StoScore[i] := 0;
- myPortfolio.Items[j].ArScore[i] := 0;
- myPortfolio.Items[j].BolScore[i] := 0;
- myPortfolio.Items[j].TotScore[i] := 0;
- end;
- end;
- end;
- if BackCheck then
- begin
- for i := 0 to simDays do
- handleBuys(myPortfolio, i, buyPercentage);
- writeln('Value: ' + toStr(myPortfolio.Cash));
- end else
- begin
- tempPort := myPortfolio;
- doRecommend(tempPort, high(tempPort.Items[0].Prices), buyPercentage);
- end;
- end.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement