/// <summary>
        /// Creates all fermion terms generated by all symmetries of a one-body orbital integral.
        /// </summary>
        /// <param name="nOrbitals">Total number of distinct orbitals.</param>
        /// <param name="orbitalIntegral">Input orbital integral.</param>
        /// <param name="indexConvention">Indexing scheme from spin-orbitals to integers.</param>
        private static IEnumerable <(HermitianFermionTerm, double)> ToOneBodySpinOrbitalTerms(
            this OrbitalIntegral orbitalIntegral,
            int nOrbitals,
            IndexConvention indexConvention)
        {
            // One-electron orbital integral symmetries
            // ij = ji
            var pqSpinOrbitals = orbitalIntegral.EnumerateOrbitalSymmetries().EnumerateSpinOrbitals();

            var coefficient = orbitalIntegral.Coefficient;

            foreach (var pq in pqSpinOrbitals)
            {
                var pInt = pq[0].ToInt(indexConvention, nOrbitals);
                var qInt = pq[1].ToInt(indexConvention, nOrbitals);
                if (pInt == qInt)
                {
                    yield return(new HermitianFermionTerm(new[] { pInt, qInt }.ToLadderSequence()), orbitalIntegral.Coefficient);
                }
                else if (pInt < qInt)
                {
                    yield return(new HermitianFermionTerm(new[] { pInt, qInt }.ToLadderSequence()), 2.0 * orbitalIntegral.Coefficient);
                }
            }
        }
        /// <summary>
        /// Creates all fermion terms generated by all symmetries of an orbital integral.
        /// </summary>
        /// <param name="nOrbitals">Total number of distinct orbitals.</param>
        /// <param name="orbitalIntegral">Input orbital integral.</param>
        /// <param name="indexConvention">Indexing scheme from spin-orbitals to integers.</param>
        /// <returns>List of fermion terms generated by all symmetries of an orbital integral.</returns>
        public static IEnumerable <(HermitianFermionTerm, double)> ToHermitianFermionTerms(
            this OrbitalIntegral orbitalIntegral,
            int nOrbitals,
            IndexConvention indexConvention = IndexConvention.UpDown)
        {
            var termType = orbitalIntegral.TermType;

            if (termType == TermType.OrbitalIntegral.OneBody)
            {
                return(orbitalIntegral.ToOneBodySpinOrbitalTerms(nOrbitals, indexConvention));
            }
            else if (termType == TermType.OrbitalIntegral.TwoBody)
            {
                return(orbitalIntegral.ToTwoBodySpinOrbitalTerms(nOrbitals, indexConvention));
            }
            else if (termType == TermType.OrbitalIntegral.Identity)
            {
                return(new List <(HermitianFermionTerm, double)>()
                {
                    (new HermitianFermionTerm(), orbitalIntegral.Coefficient)
                });
            }
            else
            {
                throw new System.NotImplementedException();
            }
        }
Beispiel #3
0
        public void UpsertConventions()
        {
            string scope = "TestConventionsScope";
            string flowConventionsCode = "GBP-6M";
            string indexConventionCode = "GBP-6M-Libor";

            // CREATE the flow conventions, index convention for swap
            var flowConventions = new FlowConventions(
                scope: scope,
                code: flowConventionsCode,
                currency: "GBP",
                paymentFrequency: "6M",
                rollConvention: "ModifiedFollowing",
                dayCountConvention: "Actual365",
                paymentCalendars: new List <string>(),
                resetCalendars: new List <string>(),
                settleDays: 2,
                resetDays: 2
                );

            var indexConvention = new IndexConvention(
                scope: scope,
                code: indexConventionCode,
                publicationDayLag: 0,
                currency: "GBP",
                paymentTenor: "6M",
                dayCountConvention: "Actual365",
                fixingReference: "BP00"
                );

            var flowConventionsResponse = _conventionsApi.UpsertFlowConventions(new UpsertFlowConventionsRequest(flowConventions));

            Assert.That(flowConventionsResponse, Is.Not.Null);
            Assert.That(flowConventionsResponse.Value, Is.Not.Null);

            var indexConventionsResponse = _conventionsApi.UpsertIndexConvention(new UpsertIndexConventionRequest(indexConvention));

            Assert.That(indexConventionsResponse, Is.Not.Null);
            Assert.That(indexConventionsResponse.Value, Is.Not.Null);

            var retrievedFlowConventions = _conventionsApi.GetFlowConventions(scope, flowConventionsCode);

            Assert.That(retrievedFlowConventions, Is.Not.Null);
            Assert.That(retrievedFlowConventions.Value.Scope, Is.EqualTo(flowConventions.Scope));
            Assert.That(retrievedFlowConventions.Value.Code, Is.EqualTo(flowConventions.Code));

            var retrievedIndexConvention = _conventionsApi.GetIndexConvention(scope, indexConventionCode);

            Assert.That(retrievedIndexConvention, Is.Not.Null);
            Assert.That(retrievedIndexConvention.Value.Scope, Is.EqualTo(indexConvention.Scope));
            Assert.That(retrievedIndexConvention.Value.Code, Is.EqualTo(indexConvention.Code));
        }
Beispiel #4
0
        /// <summary>
        ///      Loads a Hamiltonian from integral data represented
        ///      in Broombridge format.
        ///      Please see the <a href="https://docs.microsoft.com/azure/quantum/user-guide/libraries/chemistry/schema/broombridge">
        ///      Broombridge documentation</a>
        ///      for further details about the
        ///      format parsed by this method.
        /// </summary>
        /// <param name="filename">The name of the file to be loaded.</param>
        /// <param name="indexConvention">
        ///     The index convention to be used in converting the loaded
        ///     electronic structure problem into a fermionic Hamiltonian.
        /// </param>
        /// <returns>
        ///      An instance of <see cref="FermionHamiltonian"/> representing the
        ///      data contained in <paramref name="filename"/>.
        /// </returns>
        public static IEnumerable <FermionHamiltonian> LoadFromBroombridge(
            string filename,
            IndexConvention indexConvention)
        {
            var broombridgeData = Deserializers.DeserializeBroombridge(filename);

            // Create electronic structure Hamiltonian
            var fermionHamiltonians = broombridgeData.ProblemDescriptions
                                      .Select(o => o.OrbitalIntegralHamiltonian
                                              .ToFermionHamiltonian(indexConvention));

            return(fermionHamiltonians);
        }
        // Takes in a standard Q# format and outputs interpretable data to text
        // Input: Problem, state, indexConvention (default), qubitEncoding (default)
        // Output: No output, see ToPauliHamiltonian for generated filed
        public static void ToQSharpFormat(
            ProblemDescription problem,
            string state = "",
            IndexConvention indexConvention = IndexConvention.UpDown,
            QubitEncoding qubitEncoding     = QubitEncoding.JordanWigner
            )
        {
            var fermionHamiltonian = problem
                                     .OrbitalIntegralHamiltonian
                                     .ToFermionHamiltonian(indexConvention);

            Auxiliary.ToPauliHamiltonian(fermionHamiltonian, qubitEncoding);
        }
        /// <summary>
        /// Sample implementation of end-to-end electronic structure problem simulation.
        /// </summary>
        /// <param name="filename"></param>
        public static void SampleWorkflow(
            string filename,
            string wavefunctionLabel,
            IndexConvention indexConvention
            )
        {
            // Deserialize Broombridge from file.
            Data broombridge = Deserializers.DeserializeBroombridge(filename);

            // A single file can contain multiple problem descriptions. Let us pick the first one.
            var problemData = broombridge.ProblemDescriptions.First();

            #region Create electronic structure Hamiltonian
            // Electronic structure Hamiltonians are usually represented compactly by orbital integrals. Let us construct
            // such a Hamiltonian from broombridge.
            OrbitalIntegralHamiltonian orbitalIntegralHamiltonian = problemData.OrbitalIntegralHamiltonian;

            // We can obtain the full fermion Hamiltonian from the more compact orbital integral representation.
            // This transformation requires us to pick a convention for converting a spin-orbital index to a single integer.
            // Let us pick one according to the formula `integer = 2 * orbitalIndex + spinIndex`.
            FermionHamiltonian fermionHamiltonian = orbitalIntegralHamiltonian.ToFermionHamiltonian(indexConvention);

            // We target a qubit quantum computer, which requires a Pauli representation of the fermion Hamiltonian.
            // A number of mappings from fermions to qubits are possible. Let us choose the Jordan–Wigner encoding.
            PauliHamiltonian pauliHamiltonian = fermionHamiltonian.ToPauliHamiltonian(QubitEncoding.JordanWigner);
            #endregion

            #region Create wavefunction Ansatzes
            // A list of trial wavefunctions can be provided in the Broombridge file. For instance, the wavefunction
            // may be a single-reference Hartree--Fock state, a multi-reference state, or a unitary coupled-cluster state.
            // In this case, Broombridge indexes the fermion operators with spin-orbitals instead of integers.
            Dictionary <string, FermionWavefunction <SpinOrbital> > inputStates = problemData.Wavefunctions ?? new Dictionary <string, FermionWavefunction <SpinOrbital> >();

            // If no states are provided, use the Hartree--Fock state.
            // As fermion operators the fermion Hamiltonian are already indexed by, we now apply the desired
            // spin-orbital -> integer indexing convention.
            FermionWavefunction <int> inputState = inputStates.ContainsKey(wavefunctionLabel)
                ? inputStates[wavefunctionLabel].ToIndexing(indexConvention)
                : fermionHamiltonian.CreateHartreeFockState(problemData.NElectrons);
            #endregion

            #region Pipe to QSharp and simulate
            // We now convert this Hamiltonian and a selected state to a format that than be passed onto the QSharp component
            // of the library that implements quantum simulation algorithms.
            var qSharpHamiltonian  = pauliHamiltonian.ToQSharpFormat();
            var qSharpWavefunction = inputState.ToQSharpFormat();
            var qSharpData         = QSharpFormat.Convert.ToQSharpFormat(qSharpHamiltonian, qSharpWavefunction);
            #endregion
        }
        /// <summary>
        /// Method for constructing a fermion Hamiltonian from an orbital integral Hamiltonina.
        /// </summary>
        /// <param name="sourceHamiltonian">Input orbital integral Hamiltonian.</param>
        /// <param name="indexConvention">Indexing scheme from spin-orbitals to integers.</param>
        /// <returns>Fermion Hamiltonian constructed from orbital integrals.</returns>
        public static FermionHamiltonian ToFermionHamiltonian(
            this OrbitalIntegralHamiltonian sourceHamiltonian,
            IndexConvention indexConvention = IndexConvention.UpDown)
        {
            var nOrbitals   = sourceHamiltonian.SystemIndices.Max() + 1;
            var hamiltonian = new FermionHamiltonian();
            Func <OrbitalIntegral, double, IEnumerable <(HermitianFermionTerm, DoubleCoeff)> > conversion =
                (orb, coeff) => new OrbitalIntegral(orb.OrbitalIndices, coeff).ToHermitianFermionTerms(nOrbitals, indexConvention)
                .Select(o => (o.Item1, o.Item2.ToDoubleCoeff()));

            foreach (var termType in sourceHamiltonian.Terms)
            {
                foreach (var term in termType.Value)
                {
                    hamiltonian.AddRange(conversion(term.Key, term.Value.Value));
                }
            }
            // Number of fermions is twice the number of orbitals.
            hamiltonian.SystemIndices = new HashSet <int>(Enumerable.Range(0, 2 * nOrbitals));
            return(hamiltonian);
        }
Beispiel #8
0
        /// <summary>
        /// Converts an electronic structure problem description
        /// into a format consumable by Q# using default settings.
        /// </summary>
        /// <param name="problem">Input electronic structure problem description.</param>
        /// <param name="state">Selected wavefunction ansatz. This uses the Hartree–Fock state by default.</param>
        /// <param name="indexConvention">Convention for mapping spin-orbit indices to integer indices.</param>
        /// <param name="qubitEncoding">Scheme for mapping fermions to qubits.</param>
        /// <returns>
        /// A representation of <paramref name="problem" /> suitable for passing to Q# simulation operations.
        /// </returns>
        public static JordanWignerEncodingData ToQSharpFormat(
            this ProblemDescription problem,
            string state = "",
            IndexConvention indexConvention = IndexConvention.UpDown,
            QubitEncoding qubitEncoding     = QubitEncoding.JordanWigner
            )
        {
            var fermionHamiltonian = problem
                                     .OrbitalIntegralHamiltonian
                                     .ToFermionHamiltonian(indexConvention);

            var wavefunction = problem.Wavefunctions.ContainsKey(state) ?
                               problem.Wavefunctions[state].ToIndexing(indexConvention) :
                               fermionHamiltonian.CreateHartreeFockState(problem.NElectrons);

            var pauliHamiltonian = fermionHamiltonian.ToPauliHamiltonian(qubitEncoding);

            var pauliHamiltonianQSharpFormat = pauliHamiltonian.ToQSharpFormat();
            var wavefunctionQSharpFormat     = wavefunction.ToQSharpFormat();

            return(QSharpFormat.Convert.ToQSharpFormat(pauliHamiltonianQSharpFormat, wavefunctionQSharpFormat));
        }
        /// <summary>
        /// Updates an instance of <see cref="FermionHamiltonian"/>
        /// with all spin-orbitals from described by a sequence of four-body orbital integrals.
        /// </summary>
        /// <param name="nOrbitals">Total number of distinct orbitals.</param>
        /// <param name="orbitalIntegral">Sequence of four-body orbital integrals.</param>
        /// <param name="indexConvention">Indexing scheme from spin-orbitals to integers.</param>
        private static IEnumerable <(HermitianFermionTerm, double)> ToTwoBodySpinOrbitalTerms(
            this OrbitalIntegral orbitalIntegral,
            int nOrbitals,
            IndexConvention indexConvention)
        {
            List <(HermitianFermionTerm, double)> fermionTerms = new List <(HermitianFermionTerm, double)>();
            // Two-electron orbital integral symmetries
            // ijkl = lkji = jilk = klij = ikjl = ljki = kilj = jlik.
            var pqrsSpinOrbitals = orbitalIntegral.EnumerateOrbitalSymmetries().EnumerateSpinOrbitals();
            var coefficient      = orbitalIntegral.Coefficient;


            // We only need to see one of these.
            // Now iterate over pqrsArray
            foreach (var pqrs in pqrsSpinOrbitals)
            {
                var p = pqrs[0];
                var q = pqrs[1];
                var r = pqrs[2];
                var s = pqrs[3];

                var pInt = p.ToInt(indexConvention, nOrbitals);
                var qInt = q.ToInt(indexConvention, nOrbitals);
                var rInt = r.ToInt(indexConvention, nOrbitals);
                var sInt = s.ToInt(indexConvention, nOrbitals);

                // Only consider terms on the lower diagonal due to Hermitian symmetry.

                // For terms with two different orbital indices, possibilities are
                // PPQQ (QQ = 0), PQPQ, QPPQ (p<q), PQQP, QPQP (p<q), QQPP (PP=0)
                // Hence, if we only count PQQP, and PQPQ, we need to double the coefficient.
                // iU jU jU iU | iU jD jD iD | iD jU jU iD | iD jD jD iD
                if (pInt == sInt && qInt == rInt && pInt < qInt)
                {   // PQQP
                    yield return(new HermitianFermionTerm(new[] { pInt, qInt, rInt, sInt }.ToLadderSequence()), 1.0 * coefficient);
                }
                else if (pInt == rInt && qInt == sInt && pInt < qInt)
                {
                    // iU jU iU jU | iD jD iD jD
                    // PQPQ
                    yield return(new HermitianFermionTerm(new[] { pInt, qInt, sInt, rInt }.ToLadderSequence()), -1.0 * coefficient);
                }
                else if (qInt == rInt && pInt < sInt && rInt != sInt && pInt != qInt)
                {
                    // PQQR
                    // For any distinct pqr, [i;j;j;k] generates PQQR ~ RQQP ~ QPRQ ~ QRPQ. We only need to record one.
                    if (rInt < sInt)
                    {
                        if (pInt < qInt)
                        {
                            yield return(new HermitianFermionTerm(new[]  { pInt, qInt, sInt, rInt }.ToLadderSequence()), -2.0 * coefficient);
                        }
                        else
                        {
                            yield return(new HermitianFermionTerm(new[]  { qInt, pInt, sInt, rInt }.ToLadderSequence()), 2.0 * coefficient);
                        }
                    }
                    else
                    {
                        if (pInt < qInt)
                        {
                            yield return(new HermitianFermionTerm(new[]  { pInt, qInt, rInt, sInt }.ToLadderSequence()), 2.0 * coefficient);
                        }
                        else
                        {
                            yield return(new HermitianFermionTerm(new[]  { qInt, pInt, rInt, sInt }.ToLadderSequence()), -2.0 * coefficient);
                        }
                    }
                }
                else if (qInt == sInt && pInt < rInt && rInt != sInt && pInt != sInt)
                {
                    // PQRQ
                    // For any distinct pqr, [i;j;k;j] generates {p, q, r, q}, {q, r, q, p}, {q, p, q, r}, {r, q, p, q}. We only need to record one.
                    if (pInt < qInt)
                    {
                        if (rInt > qInt)
                        {
                            yield return(new HermitianFermionTerm(new[]  { pInt, qInt, rInt, sInt }.ToLadderSequence()), 2.0 * coefficient);
                        }
                        else
                        {
                            yield return(new HermitianFermionTerm(new[]  { pInt, qInt, sInt, rInt }.ToLadderSequence()), -2.0 * coefficient);
                        }
                    }
                    else
                    {
                        yield return(new HermitianFermionTerm(new[]  { qInt, pInt, rInt, sInt }.ToLadderSequence()), -2.0 * coefficient);
                    }
                }
                else if (pInt < qInt && pInt < rInt && pInt < sInt && qInt != rInt && qInt != sInt && rInt != sInt)
                {
                    // PQRS
                    // For any distinct pqrs, [i;j;k;l] generates
                    // {{p, q, r, s}<->{s, r, q, p}<->{q, p, s, r}<->{r, s, p, q},
                    // {1,2,3,4}<->{4,3,2,1}<->{2,1,4,3}<->{3,4,1,2}
                    // {p, r, q, s}<->{s, q, r, p}<->{r, p, s, q}<->{q, s, p, r}}
                    // 1324, 4231, 3142, 2413
                    if (rInt < sInt)
                    {
                        yield return(new HermitianFermionTerm(new[]  { pInt, qInt, sInt, rInt }.ToLadderSequence()), -2.0 * coefficient);
                    }
                    else
                    {
                        yield return(new HermitianFermionTerm(new[]  { pInt, qInt, rInt, sInt }.ToLadderSequence()), 2.0 * coefficient);
                    }
                }
            }
        }
Beispiel #10
0
        public void DemonstrateCreationOfSwaption()
        {
            // CREATE an Interest Rate Swap (IRS)
            var startDate    = new DateTimeOffset(2020, 2, 7, 0, 0, 0, TimeSpan.Zero);
            var maturityDate = new DateTimeOffset(2030, 2, 7, 0, 0, 0, TimeSpan.Zero);

            // CREATE the flow conventions, index convention for swap
            var flowConventions = new FlowConventions(
                scope: null,
                code: null,
                currency: "GBP",
                paymentFrequency: "6M",
                rollConvention: FlowConventions.RollConventionEnum.MF,
                dayCountConvention: FlowConventions.DayCountConventionEnum.Act365,
                holidayCalendars: new List <string>(),
                settleDays: 2,
                resetDays: 2
                );

            var idxConvention = new IndexConvention(
                code: "GbpLibor6m",
                publicationDayLag: 0,
                currency: "GBP",
                paymentTenor: "6M",
                dayCountConvention: IndexConvention.DayCountConventionEnum.Act365,
                fixingReference: "BP00"
                );

            // CREATE the leg definitions
            var fixedLegDef = new LegDefinition(
                rateOrSpread: 0.05m, // fixed leg rate (swap rate)
                stubType: LegDefinition.StubTypeEnum.Front,
                payReceive: LegDefinition.PayReceiveEnum.Pay,
                notionalExchangeType: LegDefinition.NotionalExchangeTypeEnum.None,
                conventions: flowConventions
                );

            var floatLegDef = new LegDefinition(
                rateOrSpread: 0.002m, // float leg spread over curve rate, often zero
                stubType: LegDefinition.StubTypeEnum.Front,
                payReceive: LegDefinition.PayReceiveEnum.Pay,
                notionalExchangeType: LegDefinition.NotionalExchangeTypeEnum.None,
                conventions: flowConventions,
                indexConvention: idxConvention
                );

            // CREATE the fixed leg
            var fixedLeg = new FixedLeg(
                notional: 100m,
                startDate: startDate,
                maturityDate: maturityDate,
                legDefinition: fixedLegDef,
                instrumentType: LusidInstrument.InstrumentTypeEnum.FixedLeg
                );

            // CREATE the floating leg
            var floatLeg = new FloatingLeg(
                notional: 100m,
                startDate: startDate,
                maturityDate: maturityDate,
                legDefinition: floatLegDef,
                instrumentType: LusidInstrument.InstrumentTypeEnum.FloatingLeg
                );

            var swap = new InterestRateSwap(
                startDate: startDate,
                maturityDate: maturityDate,
                legs: new List <InstrumentLeg>
            {
                floatLeg,
                fixedLeg
            },
                instrumentType: LusidInstrument.InstrumentTypeEnum.InterestRateSwap
                );

            // CREATE swaption to upsert to LUSID
            var swaption = new InterestRateSwaption(
                startDate: new DateTimeOffset(2020, 1, 15, 0, 0, 0, TimeSpan.Zero),
                payOrReceiveFixed: InterestRateSwaption.PayOrReceiveFixedEnum.Pay,
                deliveryMethod: InterestRateSwaption.DeliveryMethodEnum.Cash,
                swap: swap,
                instrumentType: LusidInstrument.InstrumentTypeEnum.InterestRateSwaption);

            // ASSERT that it was created
            Assert.That(swaption, Is.Not.Null);
            Assert.That(swaption.Swap, Is.Not.Null);

            // CAN NOW UPSERT TO LUSID
            string uniqueId = "id-swaption-1";

            UpsertOtcToLusid(swaption, "some-name-for-this-swaption", uniqueId);

            // CAN NOW QUERY FROM LUSID
            var retrieved = QueryOtcFromLusid(uniqueId);

            Assert.That(retrieved.InstrumentType == LusidInstrument.InstrumentTypeEnum.InterestRateSwaption);
            var roundTripSwaption = retrieved as InterestRateSwaption;

            Assert.That(roundTripSwaption, Is.Not.Null);
            Assert.That(roundTripSwaption.DeliveryMethod, Is.EqualTo(swaption.DeliveryMethod));
            Assert.That(roundTripSwaption.StartDate, Is.EqualTo(swaption.StartDate));
            Assert.That(roundTripSwaption.PayOrReceiveFixed, Is.EqualTo(swaption.PayOrReceiveFixed));
            Assert.That(roundTripSwaption.Swap, Is.Not.Null);
            Assert.That(roundTripSwaption.Swap.InstrumentType, Is.EqualTo(LusidInstrument.InstrumentTypeEnum.InterestRateSwap));
        }
 /// <summary>
 /// Converts spin-orbital indices to integer indices
 /// </summary>
 /// <param name="wavefunction">A fermionic wavefunction whose spin-orbital indices are to be converted.</param>
 /// <param name="indexConvention">The convention for mapping spin-orbitals to indices to be used in converting the spin-orbital indices of <paramref name="wavefunction" />.</param>
 /// <returns>
 /// A fermion wavefunction where spin-orbitals are indexed by integers
 /// according to the chosen indexing scheme.
 /// </returns>
 public static FermionWavefunction <int> ToIndexing(this FermionWavefunction <SpinOrbital> wavefunction, IndexConvention indexConvention)
 => new FermionWavefunction <int>()
 {
     Method  = wavefunction.Method,
     Energy  = wavefunction.Energy,
     SCFData = wavefunction.SCFData.SelectIndex <int>((x) => x.ToInt(indexConvention)),
     MCFData = wavefunction.MCFData.SelectIndex <int>((x) => x.ToInt(indexConvention)),
     UCCData = wavefunction.UCCData.SelectIndex <int>((x) => x.ToInt(indexConvention))
 };
Beispiel #12
0
 /// <summary>
 /// This maps the separate orbital and spin indices of a <c>SpinOrbital</c>
 /// to a single integer index.
 /// </summary>
 /// <param name="nOrbitals">The total number of orbitals.</param>
 public int ToInt(IndexConvention indexConvention, int nOrbitals = maxOrbital) =>
 indexConvention == IndexConvention.UpDown ? Orbital * 2 + Spin : Orbital + nOrbitals * Spin;
        public void DemonstrateCreationOfSwap()
        {
            // CREATE an Interest Rate Swap (IRS) (that can then be upserted into LUSID)
            var startDate    = new DateTimeOffset(2020, 2, 7, 0, 0, 0, TimeSpan.Zero);
            var maturityDate = new DateTimeOffset(2030, 2, 7, 0, 0, 0, TimeSpan.Zero);

            // CREATE the flow conventions, index convention
            var flowConventions = new FlowConventions(
                scope: null,
                code: null,
                currency: "GBP",
                paymentFrequency: "6M",
                rollConvention: "MF",
                dayCountConvention: "Act365",
                paymentCalendars: new List <string>(),
                resetCalendars: new List <string>(),
                settleDays: 2,
                resetDays: 2
                );

            var idxConvention = new IndexConvention(
                code: "GbpLibor6m",
                publicationDayLag: 0,
                currency: "GBP",
                paymentTenor: "6M",
                dayCountConvention: "Act365",
                fixingReference: "BP00"
                );

            // CREATE the leg definitions
            var fixedLegDef = new LegDefinition(
                rateOrSpread: 0.05m, // fixed leg rate (swap rate)
                stubType: "Front",
                payReceive: "Pay",
                notionalExchangeType: "None",
                conventions: flowConventions
                );

            var floatLegDef = new LegDefinition(
                rateOrSpread: 0.002m, // float leg spread over curve rate, often zero
                stubType: "Front",
                payReceive: "Pay",
                notionalExchangeType: "None",
                conventions: flowConventions,
                indexConvention: idxConvention
                );

            // CREATE the fixed leg
            var fixedLeg = new FixedLeg(
                notional: 100m,
                startDate: startDate,
                maturityDate: maturityDate,
                legDefinition: fixedLegDef,
                instrumentType: LusidInstrument.InstrumentTypeEnum.FixedLeg
                );

            // CREATE the floating leg
            var floatLeg = new FloatingLeg(
                notional: 100m,
                startDate: startDate,
                maturityDate: maturityDate,
                legDefinition: floatLegDef,
                instrumentType: LusidInstrument.InstrumentTypeEnum.FloatingLeg
                );

            var irs = new InterestRateSwap(
                startDate: startDate,
                maturityDate: maturityDate,
                legs: new List <InstrumentLeg>
            {
                floatLeg,
                fixedLeg
            },
                instrumentType: LusidInstrument.InstrumentTypeEnum.InterestRateSwap
                );

            // ASSERT that it was created
            Assert.That(irs, Is.Not.Null);

            // CAN NOW UPSERT TO LUSID
            string uniqueId = "id-swap-1";

            UpsertOtcToLusid(irs, "some-name-for-this-swap", uniqueId);

            // CAN NOW QUERY FROM LUSID
            var retrieved = QueryOtcFromLusid(uniqueId);

            Assert.That(retrieved.InstrumentType == LusidInstrument.InstrumentTypeEnum.InterestRateSwap);
            var retrSwap = retrieved as InterestRateSwap;

            Assert.That(retrSwap, Is.Not.Null);
            Assert.That(retrSwap.MaturityDate, Is.EqualTo(irs.MaturityDate));
            Assert.That(retrSwap.StartDate, Is.EqualTo(irs.StartDate));
            Assert.That(retrSwap.Legs.Count, Is.EqualTo(irs.Legs.Count));
        }