From 0a052ca840added7a831ceeba6bb5a8be2bdb33a Mon Sep 17 00:00:00 2001
From: Lance-88 <129681882+Lance-88@users.noreply.github.com>
Date: Thu, 19 Jun 2025 14:37:15 +0200
Subject: [PATCH 1/6] Fork basics
---
.gitignore | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/.gitignore b/.gitignore
index bcfa3b4..ee1dbc9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -130,4 +130,8 @@ $RECYCLE.BIN/
# Mac desktop service store files
.DS_Store
-_NCrunch*
\ No newline at end of file
+_NCrunch*
+/Bots/AleixBot/.vs
+/Bots/ExampleTraderBot/.vs/ExampleTraderBot
+/Source/.vs
+/Build/Results
From 2f969588bdc7adfc1e766abd277b157154e3940e Mon Sep 17 00:00:00 2001
From: Lance-88 <129681882+Lance-88@users.noreply.github.com>
Date: Thu, 19 Jun 2025 14:49:29 +0200
Subject: [PATCH 2/6] First fork
Test
---
Bots/AleixBot/AleixBot.cs | 18 ++++++++++++++++++
Bots/AleixBot/AleixBot.csproj | 23 +++++++++++++++++++++++
Bots/AleixBot/AleixBot.sln | 22 ++++++++++++++++++++++
3 files changed, 63 insertions(+)
create mode 100644 Bots/AleixBot/AleixBot.cs
create mode 100644 Bots/AleixBot/AleixBot.csproj
create mode 100644 Bots/AleixBot/AleixBot.sln
diff --git a/Bots/AleixBot/AleixBot.cs b/Bots/AleixBot/AleixBot.cs
new file mode 100644
index 0000000..e031fbc
--- /dev/null
+++ b/Bots/AleixBot/AleixBot.cs
@@ -0,0 +1,18 @@
+using NasdaqTrader.Bot.Core;
+
+namespace AleixBot;
+
+public class AleixBot : ITraderBot
+{
+ public string CompanyName => "Beginner Investments";
+
+ public void DoTurn(ITraderSystemContext systemContext)
+ {
+ var listings = systemContext.GetListings();
+ var cash = systemContext.GetCurrentCash(this);
+ var currentDate = systemContext.CurrentDate;
+ var tradesLeft = systemContext.GetTradesLeftForToday(this);
+
+ systemContext.BuyStock(this, listings[0], 1);
+ }
+}
\ No newline at end of file
diff --git a/Bots/AleixBot/AleixBot.csproj b/Bots/AleixBot/AleixBot.csproj
new file mode 100644
index 0000000..dda88a4
--- /dev/null
+++ b/Bots/AleixBot/AleixBot.csproj
@@ -0,0 +1,23 @@
+
+
+
+ net8.0
+ enable
+ enable
+
+
+
+ ..\..\Build\Bots
+ false
+
+
+ ..\..\Build\Bots
+ false
+
+
+
+ ..\..\Build\NasdaqTrader.Bot.Core.dll
+
+
+
+
diff --git a/Bots/AleixBot/AleixBot.sln b/Bots/AleixBot/AleixBot.sln
new file mode 100644
index 0000000..9fb532a
--- /dev/null
+++ b/Bots/AleixBot/AleixBot.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.12.35527.113 d17.12
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AleixBot", "AleixBot.csproj", "{4EED0EB0-3BBC-41E5-A1F1-AB1C2A9DDB36}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {4EED0EB0-3BBC-41E5-A1F1-AB1C2A9DDB36}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {4EED0EB0-3BBC-41E5-A1F1-AB1C2A9DDB36}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {4EED0EB0-3BBC-41E5-A1F1-AB1C2A9DDB36}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {4EED0EB0-3BBC-41E5-A1F1-AB1C2A9DDB36}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
From b1d189f8ada6a3f6a386d083483bb82580ca4ed2 Mon Sep 17 00:00:00 2001
From: Lance-88 <129681882+Lance-88@users.noreply.github.com>
Date: Thu, 19 Jun 2025 14:52:07 +0200
Subject: [PATCH 3/6] update basic bot
---
Bots/AleixBot/AleixBot.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Bots/AleixBot/AleixBot.cs b/Bots/AleixBot/AleixBot.cs
index e031fbc..28c230f 100644
--- a/Bots/AleixBot/AleixBot.cs
+++ b/Bots/AleixBot/AleixBot.cs
@@ -6,7 +6,7 @@ public class AleixBot : ITraderBot
{
public string CompanyName => "Beginner Investments";
- public void DoTurn(ITraderSystemContext systemContext)
+ public async Task DoTurn(ITraderSystemContext systemContext)
{
var listings = systemContext.GetListings();
var cash = systemContext.GetCurrentCash(this);
From 00c509b8cd42b83c30d9c8a1cd99536f689511a4 Mon Sep 17 00:00:00 2001
From: Lance-88 <129681882+Lance-88@users.noreply.github.com>
Date: Thu, 19 Jun 2025 16:45:27 +0200
Subject: [PATCH 4/6] No gitignore
Whoops
---
.gitignore | 4 ----
1 file changed, 4 deletions(-)
diff --git a/.gitignore b/.gitignore
index f9e890f..c4c704b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -132,7 +132,3 @@ $RECYCLE.BIN/
.DS_Store
_NCrunch*
-/Bots/AleixBot/.vs
-/Bots/ExampleTraderBot/.vs/ExampleTraderBot
-/Source/.vs
-/Build/Results
From c94c680e0b234415eb79f524e1b3667ba3718dc3 Mon Sep 17 00:00:00 2001
From: Lance-88 <129681882+Lance-88@users.noreply.github.com>
Date: Wed, 27 Aug 2025 09:01:57 +0200
Subject: [PATCH 5/6] =?UTF-8?q?Nieuwe=20bot=20die=20w=C3=A9l=20iets=20kan?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Bots/AleixBot.Tests/AleixBot.Tests.csproj | 27 ++++++
Bots/AleixBot.Tests/ListingPickerTests.cs | 24 +++++
Bots/AleixBot/AleixBot.cs | 69 +++++++++++++-
Bots/AleixBot/AleixBot.sln | 11 ++-
Bots/AleixBot/ListingPicker.cs | 89 +++++++++++++++++++
Bots/AleixBot/Models/IntermediateListing.cs | 5 ++
Bots/AleixBot/Models/Period.cs | 3 +
.../Models/WindowedSumPerListingPerDate.cs | 3 +
Bots/AleixBot/Properties/launchSettings.json | 11 +++
9 files changed, 240 insertions(+), 2 deletions(-)
create mode 100644 Bots/AleixBot.Tests/AleixBot.Tests.csproj
create mode 100644 Bots/AleixBot.Tests/ListingPickerTests.cs
create mode 100644 Bots/AleixBot/ListingPicker.cs
create mode 100644 Bots/AleixBot/Models/IntermediateListing.cs
create mode 100644 Bots/AleixBot/Models/Period.cs
create mode 100644 Bots/AleixBot/Models/WindowedSumPerListingPerDate.cs
create mode 100644 Bots/AleixBot/Properties/launchSettings.json
diff --git a/Bots/AleixBot.Tests/AleixBot.Tests.csproj b/Bots/AleixBot.Tests/AleixBot.Tests.csproj
new file mode 100644
index 0000000..037d1e7
--- /dev/null
+++ b/Bots/AleixBot.Tests/AleixBot.Tests.csproj
@@ -0,0 +1,27 @@
+
+
+
+ net9.0
+ latest
+ enable
+ enable
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Bots/AleixBot.Tests/ListingPickerTests.cs b/Bots/AleixBot.Tests/ListingPickerTests.cs
new file mode 100644
index 0000000..40fc9b8
--- /dev/null
+++ b/Bots/AleixBot.Tests/ListingPickerTests.cs
@@ -0,0 +1,24 @@
+namespace AleixBot.Tests
+{
+ public class Tests
+ {
+ private ListingPicker _sut;
+
+ [SetUp]
+ public void Setup()
+ {
+
+ }
+
+ //[Test]
+ //public void ListingPicker_CalculateBestListingForDate(DateOnly date)
+ //{
+ // Assert.Pass();
+ //}
+
+
+ //Initializes
+ //Returns best listing available for a specific date
+
+ }
+}
diff --git a/Bots/AleixBot/AleixBot.cs b/Bots/AleixBot/AleixBot.cs
index 28c230f..c543aa5 100644
--- a/Bots/AleixBot/AleixBot.cs
+++ b/Bots/AleixBot/AleixBot.cs
@@ -1,10 +1,15 @@
using NasdaqTrader.Bot.Core;
+using System.Diagnostics;
+using System.Diagnostics.Metrics;
namespace AleixBot;
public class AleixBot : ITraderBot
{
public string CompanyName => "Beginner Investments";
+ public static ListingPicker _listingPicker = null;
+ private static int _counter = 0;
+ private const int WINDOWSIZE = 3;
public async Task DoTurn(ITraderSystemContext systemContext)
{
@@ -13,6 +18,68 @@ public async Task DoTurn(ITraderSystemContext systemContext)
var currentDate = systemContext.CurrentDate;
var tradesLeft = systemContext.GetTradesLeftForToday(this);
- systemContext.BuyStock(this, listings[0], 1);
+ if (_listingPicker == null)
+ {
+ InitializeListingPicker(listings, WINDOWSIZE);
+ }
+
+ if (_counter % WINDOWSIZE == 0 || _counter == 0)
+ {
+ //TODO implement while loop for trading
+ if (tradesLeft <= 0)
+ {
+ _counter++;
+ return;
+ }
+
+ if (systemContext.GetHoldings(this).Any() && tradesLeft > 0)
+ {
+ tradesLeft = Sell(systemContext, tradesLeft);
+ }
+
+ cash = systemContext.GetCurrentCash(this);
+
+ if (tradesLeft > 0 && cash > 0)
+ {
+ tradesLeft = Buy(systemContext, cash, currentDate, tradesLeft);
+ }
+ }
+
+ _counter++;
+ }
+
+ private int Buy(ITraderSystemContext systemContext, decimal cash, DateOnly currentDate, int tradesLeft)
+ {
+ var listing = _listingPicker.GetXBestListingForDate(1, currentDate, cash);
+ var pricePoint = listing?.PricePoints.FirstOrDefault(l => l.Date == currentDate);
+
+ if (pricePoint is not null && cash >= pricePoint.Price)
+ {
+ systemContext.BuyStock(this, listing, (int)(cash / pricePoint.Price));
+ tradesLeft--;
+ }
+
+ return tradesLeft;
+ }
+
+ private int Sell(ITraderSystemContext systemContext, int tradesLeft)
+ {
+ var holding = systemContext.GetHoldings(this).OrderByDescending(h => h.Amount).FirstOrDefault();
+ if (holding != null)
+ {
+ systemContext.SellStock(this, holding.Listing, holding.Amount);
+ tradesLeft--;
+ }
+
+ return tradesLeft;
+ }
+
+ private static void InitializeListingPicker(System.Collections.ObjectModel.ReadOnlyCollection listings, int windowSize)
+ {
+ var sw = new Stopwatch();
+ sw.Start();
+ _listingPicker = new ListingPicker(listings, windowSize);
+ sw.Stop();
+ Debug.WriteLine($"Building ListingPicker took {sw.ElapsedMilliseconds} milliseconds");
}
}
\ No newline at end of file
diff --git a/Bots/AleixBot/AleixBot.sln b/Bots/AleixBot/AleixBot.sln
index 9fb532a..8f2ed5d 100644
--- a/Bots/AleixBot/AleixBot.sln
+++ b/Bots/AleixBot/AleixBot.sln
@@ -1,10 +1,12 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
-VisualStudioVersion = 17.12.35527.113 d17.12
+VisualStudioVersion = 17.12.35527.113
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AleixBot", "AleixBot.csproj", "{4EED0EB0-3BBC-41E5-A1F1-AB1C2A9DDB36}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AleixBot.Tests", "..\AleixBot.Tests\AleixBot.Tests.csproj", "{716FB5B8-EB7F-4FC1-90C7-7FD2FAE3DBA4}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -15,8 +17,15 @@ Global
{4EED0EB0-3BBC-41E5-A1F1-AB1C2A9DDB36}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4EED0EB0-3BBC-41E5-A1F1-AB1C2A9DDB36}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4EED0EB0-3BBC-41E5-A1F1-AB1C2A9DDB36}.Release|Any CPU.Build.0 = Release|Any CPU
+ {716FB5B8-EB7F-4FC1-90C7-7FD2FAE3DBA4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {716FB5B8-EB7F-4FC1-90C7-7FD2FAE3DBA4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {716FB5B8-EB7F-4FC1-90C7-7FD2FAE3DBA4}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {716FB5B8-EB7F-4FC1-90C7-7FD2FAE3DBA4}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {C00082EE-EABB-41B9-A550-6A1DEB725E5E}
+ EndGlobalSection
EndGlobal
diff --git a/Bots/AleixBot/ListingPicker.cs b/Bots/AleixBot/ListingPicker.cs
new file mode 100644
index 0000000..fa8abf4
--- /dev/null
+++ b/Bots/AleixBot/ListingPicker.cs
@@ -0,0 +1,89 @@
+using AleixBot.Models;
+using NasdaqTrader.Bot.Core;
+using System.Collections.ObjectModel;
+
+namespace AleixBot;
+
+public class ListingPicker
+{
+ public ReadOnlyCollection Listings { get; }
+ public int WindowSize { get; }
+ public Collection IntermediateListings { get; } = [];
+ public List WindowedListingSumPerDate = [];
+
+ private List _periods = [];
+
+ public ListingPicker(ReadOnlyCollection listings, int windowSize)
+ {
+ Listings = listings;
+ WindowSize = windowSize;
+ ConstructIntermediateDictionary();
+ }
+
+ public void ConstructIntermediateDictionary()
+ {
+
+ foreach (var listing in Listings)
+ {
+ for (int i = 0; i < listing.PricePoints.Length - 2; i++)
+ {
+ var date = listing.PricePoints[i].Date;
+ var priceDifference = listing.PricePoints[i + 1].Price - listing.PricePoints[i].Price;
+ IntermediateListings.Add(new IntermediateListing(listing.Name, date, priceDifference, listing.PricePoints[i].Price));
+ }
+ }
+
+ var allDates = IntermediateListings.Select(il => il.Date);
+ if (!allDates.Any()) return;
+
+ DateOnly begindate = allDates.Min();
+ DateOnly endDate = allDates.Max();
+
+ var groupedIntermediateListings = IntermediateListings
+ .GroupBy(il => il.Name)
+ .ToDictionary(g => g.Key, g => g.ToList());
+
+ DateOnly j = begindate;
+ while (j.AddDays(WindowSize) < endDate)
+ {
+ _periods.Add(new Period(j, j.AddDays(WindowSize)));
+ j = j.AddDays(WindowSize);
+ }
+
+ foreach (var (name, listings) in groupedIntermediateListings)
+ {
+ foreach (var period in _periods)
+ {
+ // Filter once per group and period
+ var windowSum = listings
+ .Where(il => il.Date >= period.Start && il.Date <= period.End)
+ .Sum(s => s.PriceDifference);
+
+ var priceOnStartDate = listings
+ .Where(il => il.Date == period.Start)
+ .Select(il => il.Price)
+ .FirstOrDefault();
+
+ WindowedListingSumPerDate.Add(new WindowedSumPerListingPerDate(period.Start, name, windowSum, priceOnStartDate));
+ }
+ }
+ }
+
+ public IStockListing? GetXBestListingForDate(int number, DateOnly date, decimal cash)
+ {
+ var periodForDate = _periods.Where(p => p.Start <= date && p.End >= date).FirstOrDefault();
+
+ if (periodForDate == null)
+ {
+ return null;
+ }
+
+ var bestListingName = WindowedListingSumPerDate
+ .Where(wl => wl.Date == periodForDate.Start && wl.PriceOnStartDate < cash)
+ .OrderByDescending(wl => wl.Sum)
+ .Select(wl => wl.Name)
+ .FirstOrDefault();
+
+ return Listings.FirstOrDefault(l => l.Name.Equals(bestListingName));
+ }
+}
\ No newline at end of file
diff --git a/Bots/AleixBot/Models/IntermediateListing.cs b/Bots/AleixBot/Models/IntermediateListing.cs
new file mode 100644
index 0000000..1321ee4
--- /dev/null
+++ b/Bots/AleixBot/Models/IntermediateListing.cs
@@ -0,0 +1,5 @@
+using NasdaqTrader.Bot.Core;
+
+namespace AleixBot.Models;
+
+public record IntermediateListing(string Name, DateOnly Date, decimal PriceDifference, decimal Price);
\ No newline at end of file
diff --git a/Bots/AleixBot/Models/Period.cs b/Bots/AleixBot/Models/Period.cs
new file mode 100644
index 0000000..8cdfc81
--- /dev/null
+++ b/Bots/AleixBot/Models/Period.cs
@@ -0,0 +1,3 @@
+namespace AleixBot.Models;
+
+internal record Period(DateOnly Start, DateOnly End);
\ No newline at end of file
diff --git a/Bots/AleixBot/Models/WindowedSumPerListingPerDate.cs b/Bots/AleixBot/Models/WindowedSumPerListingPerDate.cs
new file mode 100644
index 0000000..7538119
--- /dev/null
+++ b/Bots/AleixBot/Models/WindowedSumPerListingPerDate.cs
@@ -0,0 +1,3 @@
+namespace AleixBot.Models;
+
+public record WindowedSumPerListingPerDate(DateOnly Date, string Name, decimal Sum, decimal PriceOnStartDate);
\ No newline at end of file
diff --git a/Bots/AleixBot/Properties/launchSettings.json b/Bots/AleixBot/Properties/launchSettings.json
new file mode 100644
index 0000000..452bd0f
--- /dev/null
+++ b/Bots/AleixBot/Properties/launchSettings.json
@@ -0,0 +1,11 @@
+{
+ "profiles": {
+ "AleixBot": {
+ "commandName": "Project"
+ },
+ "Run Game": {
+ "commandName": "Executable",
+ "executablePath": "C:\\Users\\AleixH\\Documents\\GitHub\\NasdaqTradeSystem\\Build\\NasdaqTrader.CLI.exe"
+ }
+ }
+}
\ No newline at end of file
From 60fff409697bf1e72b2428c605e1daa89623e7db Mon Sep 17 00:00:00 2001
From: Lance-88 <129681882+Lance-88@users.noreply.github.com>
Date: Thu, 28 Aug 2025 16:52:21 +0200
Subject: [PATCH 6/6] Downgrade to .NET8
---
Bots/AleixBot.Tests/AleixBot.Tests.csproj | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Bots/AleixBot.Tests/AleixBot.Tests.csproj b/Bots/AleixBot.Tests/AleixBot.Tests.csproj
index 037d1e7..4d0eea2 100644
--- a/Bots/AleixBot.Tests/AleixBot.Tests.csproj
+++ b/Bots/AleixBot.Tests/AleixBot.Tests.csproj
@@ -1,7 +1,7 @@
- net9.0
+ net8.0
latest
enable
enable